package org.jboss.seam.faces;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.PerNestedConversation;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.AbstractMutable;
import org.jboss.seam.core.Conversation;
import org.jboss.seam.navigation.Pages;
/**
* Convenient API for performing browser redirects with
* parameters.
*
* @author Gavin King
*/
@Name("org.jboss.seam.faces.redirect")
@BypassInterceptors
@Scope(ScopeType.CONVERSATION)
@Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
@PerNestedConversation
public class Redirect extends AbstractMutable implements Serializable
{
private static final long serialVersionUID = 6947384474861235210L;
private String viewId;
private Map<String, Object> parameters = new HashMap<String, Object>();
private boolean conversationPropagationEnabled = true;
private boolean conversationBegun;
/**
* Get the JSF view id to redirect to
*/
public String getViewId()
{
return viewId;
}
/**
* Set the JSF view id to redirect to
*
* @param viewId any JSF view id
*/
public void setViewId(String viewId)
{
setDirty(this.viewId, viewId);
this.viewId = viewId;
}
/**
* Get all the request parameters that have been set
*/
public Map<String, Object> getParameters()
{
return parameters;
}
/**
* Set a request parameter value (to set a multi-valued
* request parameter, pass an array or collection as
* the value)
*/
public void setParameter(String name, Object value)
{
Object old = parameters.put(name, value);
setDirty(old, value);
}
/**
* Capture the view id and request parameters from the
* current request and squirrel them away so we can
* return here later in the conversation.
*
* @deprecated use captureCurrentView()
*/
public void captureCurrentRequest()
{
parameters.clear();
FacesContext context = FacesContext.getCurrentInstance();
parameters.putAll( context.getExternalContext().getRequestParameterMap() );
viewId = Pages.getViewId(context);
setDirty();
}
/**
* Capture the view id, request parameters and page parameters (which take
* precedence) from the current request and squirrel them away so we can
* return here later in the conversation. If no conversation is active,
* begin a conversation. The conversation is terminated by {@link
* Redirect#returnToCapturedView()} if begun by this method.
*
* @see Redirect#returnToCapturedView()
*/
public void captureCurrentView()
{
FacesContext context = FacesContext.getCurrentInstance();
// If this isn't a faces request then just return
if (context == null) return;
// first capture all request parameters
parameters.putAll( context.getExternalContext().getRequestParameterMap() );
// then preserve page parameters, overwriting request parameters with same names
parameters.putAll( Pages.instance().getStringValuesFromPageContext(context) );
// special case only needed for actionMethod if decide not to capture all request parameters
//if (context.getExternalContext().getRequestParameterMap().containsKey("actionMethod"))
//{
// parameters.put("actionMethod", context.getExternalContext().getRequestParameterMap().get("actionMethod"));
//}
viewId = Pages.getViewId(context);
conversationBegun = Conversation.instance().begin(true, false);
setDirty();
//if the request ends with an exception,
//the conversation context never gets
//flushed....
Contexts.getConversationContext().flush();
}
/**
* Should the conversation be propagated across the redirect?
* @return true by default
*/
public boolean isConversationPropagationEnabled()
{
return conversationPropagationEnabled;
}
/**
* Note that conversations are propagated by default
*/
public void setConversationPropagationEnabled(boolean conversationPropagationEnabled)
{
this.conversationPropagationEnabled = conversationPropagationEnabled;
}
/**
* Perform the redirect
*/
public void execute()
{
FacesManager.instance().redirect(viewId, parameters, conversationPropagationEnabled, true);
}
/**
* Redirect to the captured view, and end any conversation
* that began in captureCurrentView().
*
*@see Redirect#captureCurrentView()
*/
public boolean returnToCapturedView()
{
if (viewId!=null)
{
if (conversationBegun)
{
Conversation.instance().end();
}
execute();
return true;
}
else
{
return false;
}
}
//TODO: replacement for Conversation.endAndRedirect()
/*public boolean returnToParentView()
{
Manager manager = Manager.instance();
String viewId = manager.getParentConversationViewId();
if (viewId==null)
{
return false;
}
else
{
manager.redirect(viewId);
return true;
}
}*/
public static Redirect instance()
{
if ( !Contexts.isConversationContextActive() )
{
throw new IllegalStateException("No active conversation context");
}
return (Redirect) Component.getInstance(Redirect.class, ScopeType.CONVERSATION);
}
}