/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Header:$
*/
package org.apache.beehive.netui.pageflow.faces.internal;
import org.apache.beehive.netui.pageflow.PageFlowUtils;
import org.apache.beehive.netui.pageflow.PageFlowController;
import org.apache.beehive.netui.pageflow.PreviousPageInfo;
import org.apache.beehive.netui.pageflow.FacesBackingBean;
import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
import org.apache.beehive.netui.pageflow.internal.InternalUtils;
import org.apache.beehive.netui.util.internal.FileUtils;
import javax.faces.application.ViewHandler;
import javax.faces.context.FacesContext;
import javax.faces.component.UIViewRoot;
import javax.faces.FacesException;
import javax.servlet.http.HttpServletRequest;
import java.util.Locale;
import java.io.IOException;
import java.io.Serializable;
/**
* Internal class used in JSF/Page Flow integration. Delegates in all cases except:
* <ul>
* <li>
* {@link #restoreView}, which prevents view restoration if we're in a request forwarded by
* {@link PageFlowNavigationHandler}.
* </li>
* <li>
* {@link #createView}, which integrates with the "navigateTo" feature in Page Flow to save/restore the
* component tree.
* </li>
* </ul>
*
* @see org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory
*/
class PageFlowViewHandler
extends ViewHandler
{
private ViewHandler _delegate;
public PageFlowViewHandler( ViewHandler delegate )
{
_delegate = delegate;
}
public Locale calculateLocale(FacesContext context)
{
return _delegate.calculateLocale( context );
}
public String calculateRenderKitId(FacesContext context)
{
return _delegate.calculateRenderKitId( context );
}
private static class PageClientState implements Serializable
{
private UIViewRoot _viewRoot;
private FacesBackingBean _backingBean;
public PageClientState( UIViewRoot viewRoot, FacesBackingBean backingBean )
{
_viewRoot = viewRoot;
_backingBean = backingBean;
}
public UIViewRoot getViewRoot()
{
return _viewRoot;
}
public FacesBackingBean getBackingBean()
{
return _backingBean;
}
}
public UIViewRoot createView(FacesContext context, String viewId)
{
Object request = context.getExternalContext().getRequest();
HttpServletRequest httpRequest = null;
//
// First, if this is a navigateTo=Jpf.NavigateTo.currentPage or a navigateTo=Jpf.NavigateTo.previousPage,
// see if we've saved view state from the original page. If so, just restore that.
//
if ( request instanceof HttpServletRequest )
{
httpRequest = ( HttpServletRequest ) request;
PageFlowRequestWrapper rw = PageFlowRequestWrapper.unwrap( httpRequest );
if ( rw != null )
{
PreviousPageInfo prevPageInfo = rw.getPreviousPageInfo( true );
if ( prevPageInfo != null )
{
Object clientState = prevPageInfo.getClientState();
if ( clientState != null && clientState instanceof PageClientState )
{
PageClientState pcs = ( PageClientState ) clientState;
InternalUtils.setFacesBackingBean( httpRequest, pcs.getBackingBean() );
return pcs.getViewRoot();
}
}
}
}
UIViewRoot viewRoot = _delegate.createView( context, viewId );
savePreviousPageInfo( httpRequest, viewId, viewRoot );
return viewRoot;
}
public String getActionURL(FacesContext context, String viewId)
{
return _delegate.getActionURL( context, viewId );
}
public String getResourceURL(FacesContext context, String path)
{
return _delegate.getResourceURL( context, path );
}
public void renderView(FacesContext context, UIViewRoot viewToRender)
throws IOException, FacesException
{
_delegate.renderView( context, viewToRender );
}
/**
* If we are in a request forwarded by {@link PageFlowNavigationHandler}, returns <code>null</code>; otherwise,
* delegates to the base ViewHandler.
*/
public UIViewRoot restoreView(FacesContext context, String viewId)
{
Object request = context.getExternalContext().getRequest();
HttpServletRequest httpRequest = null;
if ( request instanceof HttpServletRequest )
{
httpRequest = ( HttpServletRequest ) request;
//
// If we did a forward in PageFlowNavigationHandler, don't try to restore the view.
//
if ( httpRequest.getAttribute( PageFlowNavigationHandler.ALREADY_FORWARDED_ATTR ) != null )
{
return null;
}
}
UIViewRoot viewRoot = _delegate.restoreView( context, viewId );
savePreviousPageInfo( httpRequest, viewId, viewRoot );
return viewRoot;
}
private static void savePreviousPageInfo( HttpServletRequest request, String viewID, UIViewRoot viewRoot )
{
//
// Save the current view state in the PreviousPageInfo structure of the current page flow.
//
if ( request != null )
{
PageFlowController curPageFlow = PageFlowUtils.getCurrentPageFlow( request );
if ( curPageFlow != null && ! curPageFlow.isPreviousPageInfoDisabled() )
{
//
// Only save the previous page info if the JSF view-ID is the same as the current forward path.
// Note that we strip the file extension from the view-ID -- different JSF implementations give
// us different things (foo.jsp vs. foo.faces).
//
viewID = FileUtils.stripFileExtension( viewID );
String currentForwardPath = FileUtils.stripFileExtension( curPageFlow.getCurrentForwardPath() );
if ( viewID.equals( currentForwardPath ) )
{
PreviousPageInfo prevPageInfo = curPageFlow.getCurrentPageInfo();
FacesBackingBean backingBean = InternalUtils.getFacesBackingBean( request );
prevPageInfo.setClientState( new PageClientState( viewRoot, backingBean ) );
}
}
}
}
public void writeState(FacesContext context) throws IOException
{
_delegate.writeState( context );
}
}