1 /*
2 * $Id: FacesContext.java,v 1.72.4.2 2008/06/11 18:03:04 rlubke Exp $
3 */
4
5 /*
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7 *
8 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
9 *
10 * The contents of this file are subject to the terms of either the GNU
11 * General Public License Version 2 only ("GPL") or the Common Development
12 * and Distribution License("CDDL") (collectively, the "License"). You
13 * may not use this file except in compliance with the License. You can obtain
14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
16 * language governing permissions and limitations under the License.
17 *
18 * When distributing the software, include this License Header Notice in each
19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
20 * Sun designates this particular file as subject to the "Classpath" exception
21 * as provided by Sun in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the License
23 * Header, with the fields enclosed by brackets [] replaced by your own
24 * identifying information: "Portions Copyrighted [year]
25 * [name of copyright owner]"
26 *
27 * Contributor(s):
28 *
29 * If you wish your version of this file to be governed by only the CDDL or
30 * only the GPL Version 2, indicate your decision by adding "[Contributor]
31 * elects to include this software in this distribution under the [CDDL or GPL
32 * Version 2] license." If you don't indicate a single choice of license, a
33 * recipient has the option to distribute your version of this file under
34 * either the CDDL, the GPL Version 2 or to extend the choice of license to
35 * its licensees as provided above. However, if you add GPL Version 2 code
36 * and therefore, elected the GPL Version 2 license, then the option applies
37 * only if the new code is made subject to such option by the copyright
38 * holder.
39 */
40
41 package javax.faces.context;
42
43
44 import java.util.Iterator;
45 import java.util.Map;
46
47 import javax.faces.application.Application;
48 import javax.faces.application.FacesMessage;
49 import javax.faces.application.FacesMessage.Severity;
50 import javax.faces.component.UIComponent;
51 import javax.faces.component.UIViewRoot;
52 import javax.faces.render.RenderKit;
53
54 import javax.el.ELContext;
55
56
57 /**
58 * <p><strong>FacesContext</strong> contains all of the per-request state
59 * information related to the processing of a single JavaServer Faces request,
60 * and the rendering of the corresponding response. It is passed to, and
61 * potentially modified by, each phase of the request processing lifecycle.</p>
62 *
63 * <p>A {@link FacesContext} instance is associated with a particular
64 * request at the beginning of request processing, by a call to the
65 * <code>getFacesContext()</code> method of the {@link FacesContextFactory}
66 * instance associated with the current web application. The instance
67 * remains active until its <code>release()</code> method is called, after
68 * which no further references to this instance are allowed. While a
69 * {@link FacesContext} instance is active, it must not be referenced
70 * from any thread other than the one upon which the servlet container
71 * executing this web application utilizes for the processing of this request.
72 * </p>
73 */
74
75 public abstract class FacesContext {
76
77
78 // -------------------------------------------------------------- Properties
79
80
81 /**
82 * <p>Return the {@link Application} instance associated with this
83 * web application.</p>
84 *
85 * @throws IllegalStateException if this method is called after
86 * this instance has been released
87 */
88 public abstract Application getApplication();
89
90
91 /**
92 * <p>Return an <code>Iterator</code> over the client identifiers for
93 * which at least one {@link javax.faces.application.FacesMessage} has been queued. If there are no
94 * such client identifiers, an empty <code>Iterator</code> is returned.
95 * If any messages have been queued that were not associated with any
96 * specific client identifier, a <code>null</code> value will be included
97 * in the iterated values. The elements in the <code>Iterator</code> must
98 * be returned in the order in which they were added with {@link #addMessage}.</p>
99 *
100 * @throws IllegalStateException if this method is called after
101 * this instance has been released
102 */
103 public abstract Iterator<String> getClientIdsWithMessages();
104
105 /**
106 * <p>Return the <code>ELContext</code> instance for this
107 * <code>FacesContext</code> instance. This <code>ELContext</code>
108 * instance has the same lifetime and scope as the
109 * <code>FacesContext</code> instance with which it is associated,
110 * and may be created lazily the first time this method is called
111 * for a given <code>FacesContext</code> instance. Upon creation of
112 * the ELContext instance, the implementation must take the
113 * following action: </p>
114 *
115 * <ul>
116 *
117 * <li><p>Call the {@link ELContext#putContext} method on the
118 * instance, passing in <code>FacesContext.class</code> and the
119 * <code>this</code> reference for the <code>FacesContext</code>
120 * instance itself.</p></li>
121 *
122 * <li><p>If the <code>Collection</code> returned by {@link
123 * javax.faces.application.Application#getELContextListeners} is
124 * non-empty, create an instance of {@link
125 * javax.el.ELContextEvent} and pass it to each {@link
126 * javax.el.ELContextListener} instance in the
127 * <code>Collection</code> by calling the {@link
128 * javax.el.ELContextListener#contextCreated} method.</p></li>
129 *
130 * </ul>
131 *
132 * <p>The default implementation throws
133 * <code>UnsupportedOperationException</code> and is provided
134 * for the sole purpose of not breaking existing applications that extend
135 * this class.</p>
136 *
137 * @throws IllegalStateException if this method is called after
138 * this instance has been released
139 *
140 * @since 1.2
141 */
142
143 public ELContext getELContext() {
144
145 Map m = (Map) getExternalContext().getRequestMap().get("com.sun.faces.util.RequestStateManager");
146 if (m != null) {
147 FacesContext impl = (FacesContext) m.get("com.sun.faces.FacesContextImpl");
148 if (impl != null) {
149 return impl.getELContext();
150 } else {
151 throw new UnsupportedOperationException();
152 }
153 }
154 throw new UnsupportedOperationException();
155
156 }
157
158 /**
159 * <p>Return the {@link ExternalContext} instance for this
160 * <code>FacesContext</code> instance.</p>
161 *
162 * @throws IllegalStateException if this method is called after
163 * this instance has been released
164 */
165 public abstract ExternalContext getExternalContext();
166
167
168 /**
169 * <p>Return the maximum severity level recorded on any
170 * {@link javax.faces.application.FacesMessage}s that has been queued, whether or not they are
171 * associated with any specific {@link UIComponent}. If no such messages
172 * have been queued, return <code>null</code>.</p>
173 *
174 * @throws IllegalStateException if this method is called after
175 * this instance has been released
176 */
177 public abstract Severity getMaximumSeverity();
178
179
180 /**
181 * <p>Return an <code>Iterator</code> over the {@link javax.faces.application.FacesMessage}s
182 * that have been queued, whether or not they are associated with any
183 * specific client identifier. If no such messages have been queued,
184 * return an empty <code>Iterator</code>. The elements of the <code>Iterator</code>
185 * must be returned in the order in which they were added with calls to {@link
186 * #addMessage}.</p>
187 *
188 * @throws IllegalStateException if this method is called after
189 * this instance has been released
190 */
191 public abstract Iterator<FacesMessage> getMessages();
192
193
194 /**
195 * <p>Return an <code>Iterator</code> over the {@link javax.faces.application.FacesMessage}s that
196 * have been queued that are associated with the specified client identifier
197 * (if <code>clientId</code> is not <code>null</code>), or over the
198 * {@link javax.faces.application.FacesMessage}s that have been queued that are not associated with
199 * any specific client identifier (if <code>clientId</code> is
200 * <code>null</code>). If no such messages have been queued, return an
201 * empty <code>Iterator</code>. The elements of the <code>Iterator</code>
202 * must be returned in the order in which they were added with calls to {@link
203 * #addMessage}.</p>
204 *
205 * @param clientId The client identifier for which messages are
206 * requested, or <code>null</code> for messages not associated with
207 * any client identifier
208 *
209 * @throws IllegalStateException if this method is called after
210 * this instance has been released
211 */
212 public abstract Iterator<FacesMessage> getMessages(String clientId);
213
214
215 /**
216 * <p>Return the {@link RenderKit} instance for the render kit identifier
217 * specified on our {@link UIViewRoot}, if there is one. If there is no
218 * current {@link UIViewRoot}, if the {@link UIViewRoot} does not have a
219 * specified <code>renderKitId</code>, or if there is no {@link RenderKit}
220 * for the specified identifier, return <code>null</code> instead.</p>
221 */
222 public abstract RenderKit getRenderKit();
223
224
225 /**
226 * <p>Return <code>true</code> if the <code>renderResponse()</code>
227 * method has been called for the current request.</p>
228 *
229 * @throws IllegalStateException if this method is called after
230 * this instance has been released
231 */
232 public abstract boolean getRenderResponse();
233
234
235 /**
236 * <p>Return <code>true</code> if the <code>responseComplete()</code>
237 * method has been called for the current request.</p>
238 *
239 * @throws IllegalStateException if this method is called after
240 * this instance has been released
241 */
242 public abstract boolean getResponseComplete();
243
244
245 /**
246 * <p>Return the {@link ResponseStream} to which components should
247 * direct their binary output. Within a given response, components
248 * can use either the ResponseStream or the ResponseWriter,
249 * but not both.
250 *
251 * @throws IllegalStateException if this method is called after
252 * this instance has been released
253 */
254 public abstract ResponseStream getResponseStream();
255
256
257 /**
258 * <p>Set the {@link ResponseStream} to which components should
259 * direct their binary output.
260 *
261 * @param responseStream The new ResponseStream for this response
262 *
263 * @throws NullPointerException if <code>responseStream</code>
264 * is <code>null</code>
265 *
266 * @throws IllegalStateException if this method is called after
267 * this instance has been released
268 */
269 public abstract void setResponseStream(ResponseStream responseStream);
270
271
272 /**
273 * <p>Return the {@link ResponseWriter} to which components should
274 * direct their character-based output. Within a given response,
275 * components can use either the ResponseStream or the ResponseWriter,
276 * but not both.
277 *
278 * @throws IllegalStateException if this method is called after
279 * this instance has been released
280 */
281 public abstract ResponseWriter getResponseWriter();
282
283
284 /**
285 * <p>Set the {@link ResponseWriter} to which components should
286 * direct their character-based output.
287 *
288 * @param responseWriter The new ResponseWriter for this response
289 *
290 * @throws IllegalStateException if this method is called after
291 * this instance has been released
292 * @throws NullPointerException if <code>responseWriter</code>
293 * is <code>null</code>
294 */
295 public abstract void setResponseWriter(ResponseWriter responseWriter);
296
297
298 /**
299 * <p>Return the root component that is associated with the this request.
300 * </p>
301 *
302 * @throws IllegalStateException if this method is called after
303 * this instance has been released
304 */
305 public abstract UIViewRoot getViewRoot();
306
307
308 /**
309 * <p>Set the root component that is associated with this request.
310 * This method can only be called by the application handler (or a
311 * class that the handler calls), and only during the <em>Invoke
312 * Application</em> phase of the request processing lifecycle.</p>
313 *
314 * @param root The new component {@link UIViewRoot} component
315 *
316 * @throws IllegalStateException if this method is called after
317 * this instance has been released
318 * @throws NullPointerException if <code>root</code>
319 * is <code>null</code>
320 */
321 public abstract void setViewRoot(UIViewRoot root);
322
323
324 // ---------------------------------------------------------- Public Methods
325
326
327 /**
328 * <p>Append a {@link javax.faces.application.FacesMessage} to the set of messages associated with
329 * the specified client identifier, if <code>clientId</code> is
330 * not <code>null</code>. If <code>clientId</code> is <code>null</code>,
331 * this {@link javax.faces.application.FacesMessage} is assumed to not be associated with any
332 * specific component instance.</p>
333 *
334 * @param clientId The client identifier with which this message is
335 * associated (if any)
336 * @param message The message to be appended
337 *
338 * @throws IllegalStateException if this method is called after
339 * this instance has been released
340 * @throws NullPointerException if <code>message</code>
341 * is <code>null</code>
342 */
343 public abstract void addMessage(String clientId, FacesMessage message);
344
345
346 /**
347 * <p>Release any resources associated with this
348 * <code>FacesContext</code> instance. Faces implementations may
349 * choose to pool instances in the associated {@link
350 * FacesContextFactory} to avoid repeated object creation and
351 * garbage collection. After <code>release()</code> is called on a
352 * <code>FacesContext</code> instance (until the
353 * <code>FacesContext</code> instance has been recycled by the
354 * implementation for re-use), calling any other methods will cause
355 * an <code>IllegalStateException</code> to be thrown.</p>
356 *
357 * <p>The implementation must call {@link #setCurrentInstance}
358 * passing <code>null</code> to remove the association between this
359 * thread and this dead <code>FacesContext</code> instance.</p>
360 *
361 * @throws IllegalStateException if this method is called after
362 * this instance has been released
363 */
364 public abstract void release();
365
366
367 /**
368 * <p>Signal the JavaServer faces implementation that, as soon as the
369 * current phase of the request processing lifecycle has been completed,
370 * control should be passed to the <em>Render Response</em> phase,
371 * bypassing any phases that have not been executed yet.</p>
372 *
373 * @throws IllegalStateException if this method is called after
374 * this instance has been released
375 */
376 public abstract void renderResponse();
377
378
379 /**
380 * <p>Signal the JavaServer Faces implementation that the HTTP response
381 * for this request has already been generated (such as an HTTP redirect),
382 * and that the request processing lifecycle should be terminated as soon
383 * as the current phase is completed.</p>
384 *
385 * @throws IllegalStateException if this method is called after
386 * this instance has been released
387 */
388 public abstract void responseComplete();
389
390
391 // ---------------------------------------------------------- Static Methods
392
393
394 /**
395 * <p>The <code>ThreadLocal</code> variable used to record the
396 * {@link FacesContext} instance for each processing thread.</p>
397 */
398 private static ThreadLocal<FacesContext> instance = new ThreadLocal<FacesContext>() {
399 protected FacesContext initialValue() { return (null); }
400 };
401
402
403 /**
404 * <p>Return the {@link FacesContext} instance for the request that is
405 * being processed by the current thread, if any.</p>
406 */
407 public static FacesContext getCurrentInstance() {
408
409 return (instance.get());
410
411 }
412
413
414 /**
415 * <p>Set the {@link FacesContext} instance for the request that is
416 * being processed by the current thread.</p>
417 *
418 * @param context The {@link FacesContext} instance for the current
419 * thread, or <code>null</code> if this thread no longer has a
420 * <code>FacesContext</code> instance.
421 *
422 */
423 protected static void setCurrentInstance(FacesContext context) {
424
425 if (context == null) {
426 instance.remove();
427 } else {
428 instance.set(context);
429 }
430
431 }
432
433
434 }