/** * See note above in run method. Just fiddle with the session to try to cause * IllegalStateExceptions before Seam takes over. * * @param state PersistentFacesState used in rendering * @throws IllegalStateException If logged out. */ private void testSession(PersistentFacesState state) throws IllegalStateException { FacesContext fc = state.getFacesContext(); Object o = fc.getExternalContext().getSession(false); if (o == null) { renderable.renderingException( new FatalRenderingException("Session has ended (User Logout?)")); } else { if (o instanceof HttpSession) { HttpSession session = (HttpSession) o; session.getAttributeNames(); } else if (o instanceof PortletSession) { PortletSession ps = (PortletSession) o; ps.getAttributeNames(); } } }
/** * Using the supplied {@link Renderable}, extract its {@link * com.icesoft.faces.webapp.xmlhttp.PersistentFacesState PersistentFacesState} and call the {@link * com.icesoft.faces.webapp.xmlhttp.PersistentFacesState#render PersistentFacesState.render} * method. * * <p>If a {@link com.icesoft.faces.webapp.xmlhttp.RenderingException RenderingException} occurs, * it is caught and the {@link Renderable#renderingException} callback is called. */ public void run() { if (renderable == null) { return; } PersistentFacesState state = renderable.getState(); // If the state is null, we can't render. It likely means that the // application has not properly updated the current state reference // to something meaningful as far as the RenderManager is concerned. This // can be due to bean scoping or not updating the state in a "best // practices" way (the constructor, a getter, etc.). It's not fatal but // the application does need to ensure that the supplied state is valid // so we throw a TransientRenderException back to the application's // Renderable implementation. if (state == null) { String msg = "unable to render, PersistentFacesState is null"; if (log.isWarnEnabled()) { log.warn(msg); } renderable.renderingException(new TransientRenderingException(msg)); return; } // This in response to an application with ServerInitiatedRendering coupled // with user interaction, and GET requests. If we don't update the thread // local, once user action creates a new ViewRoot, the Render thread's // version of state would forever be detached from the real view, resulting // in no more updates state.setCurrentInstance(); // JIRA case ICE-1365 // Server-side render calls can potentially be called from threads // that are outside the context of the web app which means that the // context classloader for the newly created thread might be unable // to access JSF artifacts. If the render is to succeed, the classloader // that created the PersistentFacesState must be correct so we ensure // that the context classloader of the new render thread is set // accordingly. If the current security policy does not allow this then // we have to hope that the appropriate class loader settings were // transferred to this new thread. If not, then the security policy // will need to be altered to allow this. state.installContextClassLoader(); try { // If the user has logged out via some Seam Identity object, then we // can't try to execute() the lifecycle, because the restoreView phase // will throw an exception, and Seam's restoreView phase listener // will catch it, meaning we're completely out of the loop. // Instead, try to discover if the Session is valid at this point // in time ourselves. Naturally, this isn't perfect, since we're not // synchronized with user interaction. if (SeamUtilities.isSeamEnvironment()) { testSession(state); } if (StaticTimerUtility.Log.isTraceEnabled()) { StaticTimerUtility.startSubjobTimer(); } // #2459 use fully synchronized version internally. state.executeAndRender(); if (StaticTimerUtility.Log.isTraceEnabled()) { StaticTimerUtility.subJobTimerComplete(); } } catch (IllegalStateException ise) { renderable.renderingException(new TransientRenderingException(ise)); } catch (RenderingException ex) { renderable.renderingException(ex); if (ex instanceof TransientRenderingException) { if (log.isTraceEnabled()) { log.trace("transient render exception", ex); } } else if (ex instanceof FatalRenderingException) { if (log.isDebugEnabled()) { log.debug("fatal render exception", ex); } } else { if (log.isErrorEnabled()) { log.error("unknown render exception", ex); } } } ThreadLocalUtility.checkThreadLocals(ThreadLocalUtility.EXITING_SERVER_PUSH); }