/**
  * 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);
  }