KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > faces > async > render > RunnableRender


1 /*
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * "The contents of this file are subject to the Mozilla Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11  * License for the specific language governing rights and limitations under
12  * the License.
13  *
14  * The Original Code is ICEfaces 1.5 open source software code, released
15  * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
16  * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
17  * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
18  *
19  * Contributor(s): _____________________.
20  *
21  * Alternatively, the contents of this file may be used under the terms of
22  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
23  * License), in which case the provisions of the LGPL License are
24  * applicable instead of those above. If you wish to allow use of your
25  * version of this file only under the terms of the LGPL License and not to
26  * allow others to use your version of this file under the MPL, indicate
27  * your decision by deleting the provisions above and replace them with
28  * the notice and other provisions required by the LGPL License. If you do
29  * not delete the provisions above, a recipient may use your version of
30  * this file under either the MPL or the LGPL License."
31  *
32  */

33
34 package com.icesoft.faces.async.render;
35
36 import com.icesoft.faces.webapp.xmlhttp.FatalRenderingException;
37 import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
38 import com.icesoft.faces.webapp.xmlhttp.RenderingException;
39 import com.icesoft.faces.webapp.xmlhttp.TransientRenderingException;
40 import com.icesoft.util.SeamUtilities;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43
44 import javax.faces.context.FacesContext;
45 import javax.servlet.http.HttpSession JavaDoc;
46 import javax.portlet.PortletSession;
47
48 /**
49  * RunnableRender implements Runnable and is designed to wrap up a {@link
50  * Renderable} so that it can be used on the {@link RenderHub}s rendering
51  * queue.
52  *
53  * @author ICEsoft Technologies, Inc.
54  */

55 class RunnableRender implements Runnable JavaDoc {
56
57     private static Log log = LogFactory.getLog(RenderHub.class);
58
59     private Renderable renderable;
60
61     public RunnableRender(Renderable renderable) {
62         this.renderable = renderable;
63     }
64
65     public Renderable getRenderable() {
66         return renderable;
67     }
68
69     /**
70      * Using the supplied {@link Renderable}, extract its {@link
71      * com.icesoft.faces.webapp.xmlhttp.PersistentFacesState
72      * PersistentFacesState} and call the {@link com.icesoft.faces.webapp.xmlhttp.PersistentFacesState#render
73      * PersistentFacesState.render} method.
74      * <p/>
75      * If a {@link com.icesoft.faces.webapp.xmlhttp.RenderingException
76      * RenderingException} occurs, it is caught and the {@link
77      * Renderable#renderingException} callback is called.
78      */

79     public void run() {
80         if (renderable == null) {
81             return;
82         }
83
84         PersistentFacesState state = renderable.getState();
85
86         //If the state is null, we can't render. It likely means that the
87
//application has not properly updated the current state reference
88
//to something meaningful as far as the RenderManager is concerned. This
89
//can be due to bean scoping or not updating the state in a "best
90
//practices" way (the constructor, a getter, etc.). It's not fatal but
91
//the application does need to ensure that the supplied state is valid
92
//so we throw a TransientRenderException back to the application's
93
//Renderable implementation.
94
if (state == null) {
95             String JavaDoc msg = "unable to render, PersistentFacesState is null";
96             if (log.isWarnEnabled()) {
97                 log.warn(msg);
98             }
99             renderable.renderingException(new TransientRenderingException(msg));
100             return;
101         }
102
103         // This in response to an application with ServerInitiatedRendering coupled
104
// with user interaction, and GET requests. If we don't update the thread
105
// local, once user action creates a new ViewRoot, the Render thread's
106
// version of state would forever be detached from the real view, resulting
107
// in no more updates
108
state.setCurrentInstance();
109
110         //JIRA case ICE-1365
111
//Server-side render calls can potentially be called from threads
112
//that are outside the context of the web app which means that the
113
//context classloader for the newly created thread might be unable
114
//to access JSF artifacts. If the render is to succeed, the classloader
115
//that created the PersistentFacesState must be correct so we ensure
116
//that the context classloader of the new render thread is set
117
//accordingly. If the current security policy does not allow this then
118
//we have to hope that the appropriate class loader settings were
119
//transferred to this new thread. If not, then the security policy
120
//will need to be altered to allow this.
121
try {
122             Thread.currentThread().setContextClassLoader( state.getRenderableClassLoader() );
123         } catch (SecurityException JavaDoc se) {
124             if (log.isDebugEnabled()) {
125                 log.debug("setting context class loader is not permitted", se);
126             }
127         }
128
129         try {
130
131             // If the user has logged out via some Seam Identity object, then we
132
// can't try to execute() the lifecycle, because the restoreView phase
133
// will throw an exception, and Seam's restoreView phase listener
134
// will catch it, meaning we're completely out of the loop.
135
// Instead, try to discover if the Session is valid at this point
136
// in time ourselves. Naturally, this isn't perfect, since we're not
137
// synchronized with user interaction.
138
if (SeamUtilities.isSeamEnvironment() ) {
139                 testSession(state);
140             }
141             state.execute();
142             state.render();
143              
144         } catch (IllegalStateException JavaDoc ise) {
145             renderable.renderingException( new TransientRenderingException( ise ));
146
147         } catch (RenderingException ex) {
148             renderable.renderingException(ex);
149             if (ex instanceof TransientRenderingException) {
150                 if (log.isTraceEnabled()) {
151                     log.trace("transient render exception", ex);
152                 }
153             } else if (ex instanceof FatalRenderingException) {
154                 if (log.isDebugEnabled()) {
155                     log.debug("fatal render exception", ex);
156                 }
157             } else {
158                 if (log.isErrorEnabled()) {
159                     log.error("unknown render exception", ex);
160                 }
161             }
162         }
163     }
164
165     /**
166      * See note above in run method. Just fiddle with the session to try to cause
167      * IllegalStateExceptions before Seam takes over.
168      *
169      * @param state PersistentFacesState used in rendering
170      * @throws IllegalStateException If logged out.
171      */

172     private void testSession(PersistentFacesState state) throws IllegalStateException JavaDoc {
173         FacesContext fc = state.getFacesContext();
174         Object JavaDoc o = fc.getExternalContext().getSession(false);
175         if (o == null) {
176             renderable.renderingException( new FatalRenderingException("Session has ended (User Logout?)") );
177         } else {
178             if (o instanceof HttpSession JavaDoc) {
179                 HttpSession JavaDoc session = (HttpSession JavaDoc) o;
180                 session.getAttributeNames();
181             } else if (o instanceof PortletSession) {
182                 PortletSession ps = (PortletSession) o;
183                 ps.getAttributeNames();
184             }
185         }
186     }
187
188
189     /**
190      * We override the equals method of Object so that we can compare
191      * RunnableRender instances against each other. Since the important pieces
192      * are "wrapped" up, we need to unwrap them to compare them correctly. For
193      * our purposes, we are really interested in whether the associated {@link
194      * com.icesoft.faces.webapp.xmlhttp.PersistentFacesState
195      * PersistentFacesState}s are equal so we "unwrap" each RunnableRender and
196      * compare the internal PersistentFacesStates.
197      *
198      * @param obj The RunnableRender to compare to.
199      * @return True if the internal PersistentFacesStates of each RunnableRender
200      * are equal. False otherwise.
201      */

202     public boolean equals(Object JavaDoc obj) {
203         if (obj == null ||
204             !(obj instanceof RunnableRender) ||
205             renderable == null) {
206             return false;
207         }
208
209         Renderable comparedRenderable = ((RunnableRender) obj).getRenderable();
210         if (comparedRenderable == null) {
211             return false;
212         }
213
214         PersistentFacesState comparedState = comparedRenderable.getState();
215         if (comparedState == null) {
216             return false;
217         }
218
219         PersistentFacesState myState = renderable.getState();
220         if (myState == null) {
221             return false;
222         }
223
224         return myState.equals(comparedState);
225     }
226 }
227
Popular Tags