Monday, October 17, 2011

How Are the Per Web Application Singleton Objects Created in the JSF Framework

In the JSF framework, there are several key classes that are the singletons for the application. They are created using the following way:
FactoryFinder --> Factory --> Singleton Object.
To guarantee that the object is a singleton, the FactoryFinder and the Factory do the following:
  1. The Factories are also singletons. So you can just use plain code to get a field object of it as a singleton too.
  2. The FactoryFinder defines all its fields and methods to be static. And it puts the code to retrieve the factoies in a synchronized block. So when you get a factory object from FactoryFinder, it will be a singleton.
  3. Now since the web app uses the static method of FactoryFinder to get the factory object, will different web applications deployed on the same server share the same factory object? The answer is "No" and it is very important. The FactoryFinder uses classloader of the specific web application to achieve this result.

Note 1: If the purpose is to just create a singleton, then there is no need to use Factory. I think the main purpose to use Factory here is to give a mechanism so the different implementations of the singleton classes can be used. Factory uses some algorithm to find and load the implementation classes.

Note 2: The factories are loaded at the startup time of the server. This is before the web application is used by any user.

In FactoryFinder, there are four factories that can be created. They are: ApplicationFactory, FacesContextFactory, LifecycleFactory, and RenderKitFactory.

Take the Application singleton as the example.

From javadoc, javax.faces.application.Application represents a per-web-application singleton object. It is created by the following:
Application application = ApplicationFactory.getApplication();

The implementation ApplicationFactoryImpl is simply the following:
private Application application;

   public Application getApplication(){
      if (application == null )
      {
         application = new ApplicationImpl();
       }
       return applicaiton;
   }
You can see that this code does not deal with thread safety. And it is not static. So this code itself does not guarantee that the returned applicaiton object will be a singleton.

The javax.faces.application.ApplicationFactory is also a per-web-application singleton. It is created by the following in FactoryFinder:
private static HashMap applicationMaps = new HashMap();
  
   public static Object getFactory(String factoryName) throws FacesException{
    validateFactoryName(factoryName);
    synchronized (applicationMaps) {
            Map appMap = getApplicationMap();
   
              Object 
      factory = null,
      factoryOrList = appMap.get(factoryName);
                if (factoryOrList != null && (!(factoryOrList instanceof List))) {
     
                    return (factoryOrList);
                }
        
                factory = getImplementationInstance(classLoader, factoryName,
          (List) factoryOrList);
         
                if (null == factory) {
                    ResourceBundle rb = LOGGER.getResourceBundle();
                    String message = rb.getString("severe.no_factory");
                    message = MessageFormat.format(message, factoryName);
                    throw new IllegalStateException(message);
                }
    
                appMap.put(factoryName, factory);
                return (factory);
        }
   
   }

So in this method, the synchronized code is used. it is guaranteed that the singleton will be returned.
Let us look at the code in more detail to see why the returned factory object is per-web application.
The line Map appMap = getApplicationMap(); creates a local Map variable appMap. The method called is the following:
private static HashMap applicationMaps = new HashMap();

private static Map getApplicationMap() {
        // Identify the web application class loader
        ClassLoader classLoader = getClassLoader();
 Map result = null;
 
 // Return any previously instantiated factory instance (of the
 // specified name) for this web application
 result = (HashMap) applicationMaps.get(classLoader);
 if (result == null) {
     result = new HashMap();
     applicationMaps.put(classLoader, result);
 }
 return result;
    }
So it is a map from the classLoader to another map. This classLoader object is different for different web applications deployed on the same server. The method is the following:
private static ClassLoader getClassLoader() throws FacesException {

        // J2EE 1.3 (and later) containers are required to make the
        // web application class loader visible through the context
        // class loader of the current thread.
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            throw new FacesException("getContextClassLoader");
        }
        return (cl);

    }
You can see that it uses the current thread to get the ClassLoader object. The static instance variable applicationMaps of the class FactoryFinder contains the following information:
classLoader --> {factoryName --> factoryObject}
So in a more strict sense, the factoryObject singleton is not a singleton across the JVM. It is a singleton inside each web applicaiton.

Thursday, October 13, 2011

Main Classes Called by the Phase Objects in JSF Lifecycle

UIViewRoot and ViewHandler

The JSF lifecycle has 6 phases. They are RestoreViewPhase, ApplyRequestValuesPhase,ProcessValidationsPhase, UpdateModelValuesPhase, InvokeApplicationPhase, and RenderResponsePhase. The corresponding classes are all in the package com.sun.faces.lifecycle.

The RestoreViewPhase gets the UIViewRoot from the facesContext or the viewhandler. Either way, it will eventually set the viewRoot in the facesContext.

The ApplyRequestValuesPhase basically uses the ViewRoot to do decoding:
public void execute(FacesContext facesContext) throws FacesException{
         ......
         UIComponent component = facesContext.getViewRoot();
         ......
         component.processDecodes(facesContext);
         .......
      }
 
The ProcessValidationsPhase basically uses the ViewRoot to invoke the validators:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processValidators(facesContext); 
          .......
       }
 
The UpdateModelValuesPhase uses the ViewRoot to process updates:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processUpdates(facesContext);
          .......
       }
The InvokeApplicationPhase uses the ViewRoot to process application:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          UIComponent component = facesContext.getViewRoot();
          ......
          component.processApplication(facesContext); 
          .......
       }
The RenderResponsePhase uses the viewHandler and the ViewRoot to render the view:
public void execute(FacesContext facesContext) throws FacesException{
          ......
          facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
          .......
       }
From the above, we can see that the ViewRoot object plays an important role. All the phases between the RestoreViewPhase and the RenderViewPhase just delegate the work to the ViewRoot.

Some Notes on UIViewRoot

The UIViewRoot class calls the broadcast(event) method of the UIComponent class in many places. The name of this method is misleading. If you look at the code, it actually does not just broadcast the event. It actually also invokes the event listeners to perform actions.
The following is the method in the UIComponentBase class:
public void broadcast(FacesEvent event)
        throws AbortProcessingException {
        if (event == null) {
            throw new NullPointerException();
        }
        if (listeners == null) {
            return;
        }
        Iterator iter = listeners.iterator();
        while (iter.hasNext()) {
            FacesListener listener = iter.next();
            if (event.isAppropriateListener(listener)) {
                event.processListener(listener);
            }
        }
    }
There are two concrete event classes that implement the processListener(...) method. One is ActionEvent, and the other is ValueChangeEvent. The ActionEvent class has the following:
public void processListener(FacesListener listener) {
        ((ActionListener) listener).processAction(this);
    }
The ValueChangeEvent class has the following:
public void processListener(FacesListener listener) {
        ((ValueChangeListener) listener).processValueChange(this);
    }
So here the event actually lets the listeners to act on the event itself. It does not just sit at the listeners.
The following are more details. The com.sun.faces.application.ActionListenerImpl has the code below:
public void processAction(ActionEvent event) {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("processAction(" + event.getComponent().getId() + ")");
        }
        UIComponent source = event.getComponent();
        ActionSource actionSource = (ActionSource) source;
        FacesContext context = FacesContext.getCurrentInstance();

        Application application = context.getApplication();

        Object invokeResult = null;
        String outcome = null;
        MethodBinding binding = null;

 binding = actionSource.getAction();
 if (binding != null) {
     try {
  if (null != (invokeResult = binding.invoke(context, null))) {
                    outcome = invokeResult.toString();
                }
                // else, default to null, as assigned above.
     } catch (MethodNotFoundException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
     catch (EvaluationException e) {
                if (logger.isLoggable(Level.SEVERE)) {
                    logger.log(Level.SEVERE, e.getMessage(), e);
                }
  throw new FacesException
                    (binding.getExpressionString() + ": " + e.getMessage(), e);
     }
 }

        // Retrieve the NavigationHandler instance..

        NavigationHandler navHandler = application.getNavigationHandler();

        // Invoke nav handling..

        navHandler.handleNavigation(context,
                                    (null != binding) ?
                                    binding.getExpressionString() : null,
                                    outcome);

        // Trigger a switch to Render Response if needed
        context.renderResponse();
    }
The javax.faces.event.MethodExpressionValueChangeListener class has the code below:
public void processValueChange(ValueChangeEvent valueChangeEvent) throws AbortProcessingException {
                         
        if (valueChangeEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {valueChangeEvent});
        } catch (ELException ee) {
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }
The javax.faces.event.MethodExpressionActionListener class has the code below:
public void processAction(ActionEvent actionEvent) throws AbortProcessingException {

        if (actionEvent == null) {
            throw new NullPointerException();
        }
        try {
            FacesContext context = FacesContext.getCurrentInstance();
            ELContext elContext = context.getELContext();
            methodExpression.invoke(elContext, new Object[] {actionEvent});
        } catch (ELException ee) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE,
                           "severe.event.exception_invoking_processaction",
                           new Object[]{
                                 ee.getCause().getClass().getName(),
                                 methodExpression.getExpressionString(),
                                 actionEvent.getComponent().getId()
                           });
                StringWriter writer = new StringWriter(1024);
                ee.getCause().printStackTrace(new PrintWriter(writer));
                LOGGER.severe(writer.toString());
            }
            throw new AbortProcessingException(ee.getMessage(), ee.getCause());
        }
    }

A Closer Look at How the InvokeApplicationPhase works

The code of the execute(...) method of the InvokeApplicationPhase is very simple. Essentially it just calls root.processApplication(facesContext) where root is the UIViewRoot. And the essential code in the processApplication(...) method of UIViewRoot is the following:
broadcastEvents(context,PhaseId.INVOKE_APPLICATION);
So let's see how it works in reality. The example used here is a simple jsp file with a form:
<html>
       ...
       <f:view>
          ...
          <h:form>
             ...
             <h:commandButton action="#{quiz.answerAction}" />
             ...
          </h:form>
         ...
       </f:view>
     </html>
Here is what happened during the lifecycle of JSF. We can see when and where the event object is created.
  1. In the ApplyRequestValuePhase, JSF iterates through all the UIComponents in the UIForm and calls the processDecodes method of each component.
  2. The CommandButton component gets the Render and lets the Render do the decode.
  3. The ButtonRender creates an ActionEvent and queues the event to the UIViewRoot. The event has the Invoke_Application phase ID and so will be used in the Invoke_Applicaiton pahse. Interestingly at this point, the events[] field of the UIViewRoot class is still null. So it is created and the ActionEvent is put in. Actually this makes sense because the events[] field in UIViewRoot class is a transient field. So it is not saved in the session and can not be restored in the Restore_View phase.
  4. In the Invoke_Applicaiton phase, the UIViewRoot will pick up this event and let it work.

Monday, October 10, 2011

How Does the JSF Restore_View Phase Restore the View?

The Restore_View phase is one of the key points in the JSF lifecycle. How does JSF restore the view? From where?

When does the Restore_View actually restore the view?

When a user navigates through various pages of an application on the brower, he or she may visit the same jsp file multiple times. A jsp file is a view in JSF. Will this view be saved by the JSF framework and then be restored in every subsequent visit? In general the answer is no. We will use jsf-1.2 in this analysis.

The java file in JSF to do the RESTORE_VIEW phase is com.sun.faces.lifecycle.RestoreViewPhase.java. Two of its methods are the following
/**
     * PRECONDITION: the necessary factories have been installed in the
     * ServletContext attr set. 
     * POSTCONDITION: The facesContext has been initialized with a tree.
     */

    public void execute(FacesContext facesContext) throws FacesException {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Entering RestoreViewPhase");
        }
        
        ......
        
        Util.getViewHandler(facesContext).initView(facesContext);        

        // If an app had explicitely set the tree in the context, use that;
        //
        UIViewRoot viewRoot = facesContext.getViewRoot();
        Locale locale = null;
        if (viewRoot != null) {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Found a pre created view in FacesContext");
            }
            locale = facesContext.getExternalContext().getRequestLocale();
            facesContext.getViewRoot().setLocale(locale);
            doPerComponentActions(facesContext, viewRoot);
            return;
        }

        ......
        
 if (isPostback(facesContext)) {
     // try to restore the view
            ViewHandler viewHandler = Util.getViewHandler(facesContext);
     if (null == (viewRoot = viewHandler.restoreView(facesContext, viewId))) {
                JSFVersionTracker tracker = 
                        ApplicationAssociate.getInstance(facesContext.getExternalContext()).getJSFVersionTracker();

  // The tracker will be null if the user turned off the 
  // version tracking feature.  
                if (null != tracker) {
      // Get the versions of the current ViewHandler and
      // StateManager.  If they are older than the current
      // version of the implementation, fall back to the
      // JSF 1.1 behavior.
                    Version toTest = tracker.
                            getVersionForTrackedClassName(viewHandler.getClass().getName());
                    Version currentVersion = tracker.getCurrentVersion();
      boolean viewHandlerIsOld = false,
   stateManagerIsOld = false;
      
      viewHandlerIsOld = (toTest.compareTo(currentVersion) < 0);
      toTest = tracker.
   getVersionForTrackedClassName(facesContext.getApplication().getStateManager().getClass().getName());
      stateManagerIsOld = (toTest.compareTo(currentVersion) < 0);

                    if (viewHandlerIsOld || stateManagerIsOld) {
                        viewRoot = viewHandler.createView(facesContext, viewId);
                        if (null != viewRoot) {
                            facesContext.renderResponse();
                        }
                    }
                }
                
                if (null == viewRoot) {
                    Object[] params = {viewId};
                    throw new ViewExpiredException(MessageUtils.getExceptionMessageString(
                            MessageUtils.RESTORE_VIEW_ERROR_MESSAGE_ID, params), viewId);
                }
     }
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Postback: Restored view for " + viewId);
            }
 }
 else {
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("New request: creating a view for " + viewId);
            }
            // if that fails, create one
            viewRoot = (Util.getViewHandler(facesContext)).
                createView(facesContext, viewId);
            facesContext.renderResponse();
        } 
        assert (null != viewRoot);

        facesContext.setViewRoot(viewRoot);
        doPerComponentActions(facesContext, viewRoot);

        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Exiting RestoreViewPhase");
        }
    }

    /**
     *
     * @return true if the request method is POST or PUT, or the method
     * is GET but there are query parameters, or the request is not an
     * instance of HttpServletRequest.
     */

    private boolean isPostback(FacesContext context) {
        // Get the renderKitId by calling viewHandler.calculateRenderKitId().
        String renderkitId = 
                context.getApplication().getViewHandler().
                calculateRenderKitId(context);
        ResponseStateManager rsm = RenderKitUtils.getResponseStateManager(context,
                renderkitId);
        return rsm.isPostback(context);
    }
A typical case is the following:

Step 1. The user visits a page the first time. And that page has a form.

Step 2. The user enters the data into the form and then submits the page.

In Step 1, JSF will execute two phases Restore_View and Render_Response. It creates the view in the Restoer_View phase. But here it is just an empty ViewRoot and it is put into the facescontext. In the Render_Response phase, JSF will creates the actual UI components and build the view. It will also save the view into the session using the class com.sun.faces.application.StateManagerImpl in this phase. In Step 2, by default, the page is submitted to the same page. JSF will go through all the phases in the lifecycle. Now looking at the method execute(...) of RestoreViewPhase, we can see an if-else clause. The condition is whether or not this mehtod

isPostback(facesContext)
will return true or false. The javadoc of this method states clearly that it will return true if the request method is POST or PUT, or the method is GET but there are query parameters, or the request is not an instance of HttpServletRequest. In our case, it is a form and method is POST, so the condition is true. Hence the view will be restored using the one saved in the session in Step 1. In a different case, suppose it is still the page that the user visited before. But this time it is a redirect as a result of the processing on the server side. Under this situation, the method isPostback(...) will return false. So even though the page has been visited before, a brand new view will be created just like in Step 1 described above. A typical case is that in the Invoke_Application phase of the lifecycle,JSF determines that everything is successful and invokes a redirect call to some page. Now no matter whether or not that page has been visited before, it will be considered to be a new request. And immmediately following the Invoke_Application phase, the actual call to the Render_Response phase will be skipped. Instead, a new JSF lifecycle will start. And since it is regarded a new request, only two phases Restore_View and Render_Response will be executed for the page that is redirected to.

So under the redirect situation, a view will be re-created just as when the page is visited the first time. But this is not the whole story. To make this more precise, there is some difference here from the first time the page is visited. In the appache tomcat implementation, when the page is visited the first time, the Render_Reponse phase also does the following:

  1. Calls the jsp compiler ( org.apache.jasper.compiler.Compiler ). This compiler will removeGeneratedFiles, generateJava, and generateClass for the jsp page. Note that the three phrases in bold are from the actual log file.
  2. Creates the managed beans used in the JSP page. If the scope of the bean is session, the bean will be stored in the session.
In the subsequest visists to the same page, these compiler actions won't happen. And the session-scoped beans do not need to be created again if it is in the same session.

A closer look at how the view is stored and retrieved

Simply put, a view is stored in the session. When a page is visited the first time, two phases Restore_View and Render_Response will be called. In the Render_Response phase, the method is the following:
public void execute(FacesContext facesContext) throws FacesException
{
   ......
   facesContext.getApplication().getViewHandler().renderView(facesContext, facesContext.getViewRoot());
   ......
}
The ViewHandler will eventually call the following:
stateManager.saveView(context);
where stateManager is an instance of com.sun.faces.applicaiton.StateManagerImpl. This method will in turn invokes the following:
/**
     * Return an opaque Object containing sufficient
     * information for this same instance to restore the state of the
     * current {@link UIViewRoot} on a subsequent request.  The returned
     * object must implement java.io.Serializable. If there
     * is no state information to be saved, return null
     * instead.
     *
     * Components may opt out of being included in the serialized view
     * by setting their transient property to true.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * and component state information.
     *
     * 

This method must also enforce the rule that, for components with * non-null ids, all components that are descendants of the * same nearest {@link NamingContainer} must have unique identifiers. * * For backwards compatability with existing * StateManager implementations, the default * implementation of this method calls {@link #saveSerializedView} * and creates and returns a two element Object array * with element zero containing the structure property * and element one containing the state property of the * SerializedView. * * @since 1.2 * * @param context {@link FacesContext} for the current request * * @throws IllegalStateException if more than one component or * facet within the same {@link NamingContainer} in this view has * the same non-null component id */ public Object saveView(FacesContext context) { SerializedView view = saveSerializedView(context); Object stateArray[] = { view.getStructure(), view.getState() }; return stateArray; }

And the method saveSerializedView(...) does all the dirty work. Basically it will create two objects treeStructure and componentState from the facesContext in the following code:
public SerializedView saveSerializedView(FacesContext context)
          throws IllegalStateException {
  SerializedView result = null;
  Object treeStructure = null;
  Object componentState = null;
  ......
  result = new SerializedView(treeStructure =
              getTreeStructureToSave(context),
                                    componentState =
                                          getComponentStateToSave(context));

  ......
Object stateArray[] = {treeStructure, componentState};
......
actualMap.put(idInActualMap, stateArray);
......
}
In the above code, the Map object actualMap is in another Map logicalMap. And the logicalMap is created in sessionMap which is an object in the session.

Now in another lifecycle when the view needs to be restored, the Restore_View phase will call viewHander.restoreView(facesContext, viewId) in its execute(...) method. And the restoreView(...) method of the ViewHandlerImpl is the following:

public UIViewRoot restoreView(FacesContext context, String viewId,
                                  String renderKitId) {
   ......
   viewRoot = Util.getStateManager(context).restore(context,viewId,renderKitId);
   ......
}
So it basically uses the StateManage again to retrieve the view saved there before.

Thursday, October 6, 2011

A Note on JSF Lifecycle and Navigation Rule

The JSF text books or tutorials usually shows a clear picture of the jsf life cycle, which contains 6 phases. In particular, the last phase is Render Response phase, which comes after the Invoke Application phase. But this does not necessarily always happen depending on how you interpret the phase.

In the following analysis, the source code of jsf-api-1.2 and jsf-impl-1.2 are used.

The core of service(...) method in FacesServlet.java is the following:

try{
      lifecycle.execute(context);
      lifecycle.render(context);
   }catch(...)
   finally{
      context.release();
   }

It is worth noting that the render phase is called separately.

In the LifecycleImpl.java, the main contents of the two methods called by the servlet are the following:

private Phase phases[] = {
   null, // ANY_PHASE placeholder, not a real phase
   new RestoreViewPhase(),
   new ApplyRequestValuesPhase(),
   new ProcessValidationPhase(),
   new UpdateModelValuesPhase(),
   new InvokeApplicationPhase()
};

public void execute(FacesContext context) throws FacesException
{
   ...
   populateFacesELResolverForJsp(context);
   
   for(int i=1; i<phases.length; i++){
   
     if ( context.getRenderResponse() || context.getResponseComplete() ){
        break;
     }
     
     phase( (PhaseId)PhaseId.VALUES.get(i), phase[i], context);
     
     if ( reload( (PhaseId) PhaseId.VALUES.get(i), context)) {
         context.renderResponse();
     }
   }
}

public void render(FacesContext context) throws FacesException
{
    ...
    if ( !context.getResponseComplete()){
        phase(PhaseId.RENDER_RESPONSE, response, context);
    }
}


Note that in the execute(...) method, only the first 5 phases are iterated. Everytime the method phase(...) is called, it will log the message indicating that it is entering this phase and then exiting this phase. This log message can actually bring confusion. When do you think the life cycle has entered Render_Response phase? I think the lifecycel enters this phase when the FacesServlet calls the lifecycle.render(context) method. In this method, if the condition context.getResponseComplete() is true, then the phase(...) call to RENDER_RESPONSE will be skipped. You will never see the log message saying that it is entering or exiting the RENDER_RESPONSE phase. And this case actually happens quite normally. The following is one typical example.

In the example application called "javaquiz" described in the book <<Core JavaServer Faces>>, the first page displays a question. The JSF life cycle only goes through two phases: Restore_View and Render_Response. Now the user types in the correct answer on the screen. The browser will show the next page. In the log file, it shows the lifecycle goes through the phases 1-5. But it does not show phase 6 (RENDER_RESPONSE). Instead, after the phases 1-5, it shows the phase 1(RESTORE_VIEW) and 6(RENDER_RESPONSE). So what happened here? The truth is that after the user submits the answer, the lifecycle goes through phases 1-5. In phase 5 ( Invoke_Application), the NavigationHandlerImpl redirects to the viewId /success.jsp. When the FacesServlet calls the render(...) method. the condition context.getResponseComplete() returns true. So it does not call phase(PhaseId.RENDER_RESPONSE, response, context). Instead, the FacesServlet invokes another lifecycle for the page success.jsp.

In the access log file of Tomcat, you can actually see the following new messages after submitting the answer on the screen. The first log message is for index.faces because this is the page you submitted. The second log message is for success.faces. You actually did not submit this request. This is the result of the redirecting from phase 5.
127.0.0.1 - - [07/Oct/2011:10:26:32 -0400] "POST /javaquiz/index.faces HTTP/1.1" 302 -
127.0.0.1 - - [07/Oct/2011:10:26:36 -0400] "GET /javaquiz/success.faces HTTP/1.1" 200 1032
The actual call by the NavigationHandlerImpl for redirecting is in the following method:
public void handleNavigation(FacesContext context, String fromAction,
                                 String outcome) {
      ...
      ExternalContext extContext = context.getExternalContext();
      ...
      extContext.redirect(newPath), 
      ...
}

The following is the javadoc of the redirect(...) method called by the NavigationHandlerImpl:

/**
* Redirect a request to the specified URL, and cause the
* responseComplete() method to be called on the
* {@link FacesContext} instance for the current request.
* Servlet: This must be accomplished by calling the
* javax.servlet.http.HttpServletResponse method
* sendRedirect().
* Portlet: This must be accomplished by calling the
* javax.portlet.ActionResponse method
* sendRedirect().
* @param url Absolute URL to which the client should be redirected
* @throws IllegalArgumentException if the specified url is relative
* @throws IllegalStateException if, in a portlet environment,
*  the current response object is a RenderResponse
*  instead of an ActionResponse
* @throws IllegalStateException if, in a servlet environment,
*  the current response has already been committed
* @throws IOException if an input/output error occurs
*/
public abstract void redirect(String url)
throws IOException;