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 log.debug("getFacesContext: running inner constructor");
74
75 _facesContext = facesContext;
76
77 if (install)
78 {
79 FacesContext.setCurrentInstance(this);
80 }
81
82 externalContextDelegate = new PortletExternalContextWrapper(
83 _facesContext.getExternalContext());
84
85 _handlers = fhandlers;
86 _nextToken = fnextToken;
87 contextLockHandler = fcontextLockHandler;
88 if (finit)
89 {
90 ListIterator i = fhandlers.listIterator();
91 try
92 {
93 contextLockHandler.init(facesContext);
94 while (i.hasNext())
95 {
96 RequestHandler h = (RequestHandler) i.next();
97
98 if (log.isDebugEnabled())
99 {
100 log.debug("Running inithandler of type "
101 + h.getClass().getName());
102 }
103
104 h.init(facesContext);
105 }
106 }
107 catch (RuntimeException e)
108 {
109 log.error("Problem initialising RequestHandler", e);
110 _release(i);
111 contextLockHandler.deinit();
112 throw e;
113 }
114 }
115 else
116 {
117 try
118 {
119 contextLockHandler.init(facesContext);
120 }
121 catch (RuntimeException e)
122 {
123 contextLockHandler.deinit();
124 }
125
126 RequestType type = ExternalContextUtils.getRequestType(facesContext
127 .getExternalContext());
128
129 if (RequestType.RENDER.equals(type))
130 {
131 String handlersKey = (String) fnextToken;
132 FrameworkAdapter adapter = (FrameworkAdapter) getExternalContext()
133 .getApplicationMap().remove(
134 REQUEST_ADAPTER + handlersKey);
135 if (FrameworkAdapter.getCurrentInstance() == null)
136 {
137 FrameworkAdapter.setCurrentInstance(adapter);
138 }
139 }
140 }
141 }
142
143 //~ Non-Final Methods -----------------------------------------------------
144
145 public void release()
146 {
147 log.debug("Running release");
148 RequestType type = ExternalContextUtils
149 .getRequestType(getExternalContext());
150 if (RequestType.RENDER.equals(type) ||
151 RequestType.EVENT.equals(type) ||
152 RequestType.RESOURCE.equals(type) ||
153 this.getResponseComplete())
154 {
155 ListIterator i = _handlers.listIterator();
156 while (i.hasNext())
157 {
158 i.next();
159 }
160 _release(i);
161 }
162 if (RequestType.ACTION.equals(type))
163 {
164 if (this.getResponseComplete())
165 {
166 // If response is complete by some reason, we need to
167 // clean request handlers from application map. This is set
168 // before an instance of this class is created.
169 getExternalContext().getApplicationMap().remove(
170 PortletOrchestraFacesContextFactory.REQUEST_HANDLERS+_nextToken);
171 }
172 else
173 {
174 //Pass the current FrameworkAdapter through application map,
175 //to remove it later when rendering
176 FrameworkAdapter adapter = FrameworkAdapter.getCurrentInstance();
177 getExternalContext().getApplicationMap().put(
178 REQUEST_ADAPTER + _nextToken, adapter);
179
180 //Orchestra suppose the same thread handles the current request, but
181 //in portlets this is not necessary true. One thread could handle action
182 //requests and other render request. To keep code working we set it to
183 //null here, so other request don't mix it.
184 FrameworkAdapter.setCurrentInstance(null);
185 }
186 }
187
188 try
189 {
190 //Since in portlets the same thread does not handler both action and
191 //render phase for the same request contextLockHandler needs to
192 //be cleared and lock again
193 contextLockHandler.deinit();
194 }
195 catch (Exception e)
196 {
197 log.error("Problem deinitialising RequestHandler", e);
198 }
199 log.debug("Release completed");
200 getWrapped().release();
201 }
202
203 @Override
204 public FacesContext getWrapped()
205 {
206 return _facesContext;
207 }
208
209 private void _release(ListIterator i)
210 {
211 while (i.hasPrevious())
212 {
213 try
214 {
215 RequestHandler h = (RequestHandler) i.previous();
216 if (log.isDebugEnabled())
217 {
218 log.debug("Running deinithandler of type "
219 + h.getClass().getName());
220 }
221 h.deinit();
222 }
223 catch (Exception e)
224 {
225 log.error("Problem deinitialising RequestHandler", e);
226 }
227 }
228 }
229
230 //~ Final Methods ---------------------------------------------------------
231
232 public ExternalContext getExternalContext()
233 {
234 return externalContextDelegate == null ? getWrapped()
235 .getExternalContext() : externalContextDelegate;
236 }
237 }