[jboss-cvs] jboss-seam/src/main/org/jboss/seam/navigation ...
Gavin King
gavin.king at jboss.com
Tue Jun 19 15:13:55 EDT 2007
User: gavin
Date: 07/06/19 15:13:55
Added: src/main/org/jboss/seam/navigation
Action.java ConversationControl.java
ConversationIdParameter.java
ELConversationIdParameter.java Input.java
Navigation.java NavigationHandler.java Output.java
Page.java Pageflow.java Pages.java Param.java
ProcessControl.java Put.java
RedirectNavigationHandler.java
RenderNavigationHandler.java Rule.java
SafeActions.java
SyntheticConversationIdParameter.java
TaskControl.java package-info.java
Log:
repackaged built-in components
sorry for breakage, but it had to happen eventually :-(
Revision Changes Path
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Action.java
Index: Action.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.core.Expressions.MethodExpression;
import org.jboss.seam.core.Expressions.ValueExpression;
public class Action
{
private MethodExpression methodExpression;
private ValueExpression valueExpression;
private String outcome;
public boolean isExecutable()
{
return valueExpression==null ||
Boolean.TRUE.equals( valueExpression.getValue() );
}
public MethodExpression getMethodExpression()
{
return methodExpression;
}
public void setMethodExpression(MethodExpression methodExpression)
{
this.methodExpression = methodExpression;
}
public ValueExpression getValueExpression()
{
return valueExpression;
}
public void setValueExpression(ValueExpression valueExpression)
{
this.valueExpression = valueExpression;
}
public String getOutcome()
{
return outcome;
}
public void setOutcome(String outcome)
{
this.outcome = outcome;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/ConversationControl.java
Index: ConversationControl.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.annotations.FlushModeType;
import org.jboss.seam.core.Conversation;
import org.jboss.seam.core.Expressions.ValueExpression;
public class ConversationControl
{
private boolean isBeginConversation;
private boolean isEndConversation;
private boolean isEndConversationBeforeRedirect;
private boolean join;
private boolean nested;
private FlushModeType flushMode;
private String pageflow;
private ValueExpression<Boolean> beginConversationCondition;
private ValueExpression<Boolean> endConversationCondition;
public boolean isBeginConversation()
{
return isBeginConversation;
}
public void setBeginConversation(boolean isBeginConversation)
{
this.isBeginConversation = isBeginConversation;
}
public boolean isEndConversation()
{
return isEndConversation;
}
public void setEndConversation(boolean isEndConversation)
{
this.isEndConversation = isEndConversation;
}
public void beginOrEndConversation()
{
if ( endConversation() )
{
if (isEndConversationBeforeRedirect)
{
Conversation.instance().endBeforeRedirect();
}
else
{
Conversation.instance().end();
}
}
if ( beginConversation() )
{
boolean begun = Conversation.instance().begin(join, nested);
if (begun)
{
if ( flushMode!=null )
{
Conversation.instance().changeFlushMode(flushMode);
}
if ( pageflow!=null )
{
Pageflow.instance().begin(pageflow);
}
}
}
}
private boolean beginConversation()
{
return isBeginConversation &&
(beginConversationCondition==null || Boolean.TRUE.equals( beginConversationCondition.getValue() ) );
}
private boolean endConversation()
{
return isEndConversation &&
(endConversationCondition==null || Boolean.TRUE.equals( endConversationCondition.getValue() ) );
}
public FlushModeType getFlushMode()
{
return flushMode;
}
public void setFlushMode(FlushModeType flushMode)
{
this.flushMode = flushMode;
}
public boolean isJoin()
{
return join;
}
public void setJoin(boolean join)
{
this.join = join;
}
public boolean isNested()
{
return nested;
}
public void setNested(boolean nested)
{
this.nested = nested;
}
public String getPageflow()
{
return pageflow;
}
public void setPageflow(String pageflow)
{
this.pageflow = pageflow;
}
public boolean isEndConversationBeforeRedirect()
{
return isEndConversationBeforeRedirect;
}
public void setEndConversationBeforeRedirect(boolean isEndConversationBeforeRedirect)
{
this.isEndConversationBeforeRedirect = isEndConversationBeforeRedirect;
}
public ValueExpression<Boolean> getBeginConversationCondition()
{
return beginConversationCondition;
}
public void setBeginConversationCondition(ValueExpression<Boolean> beginConversationCondition)
{
this.beginConversationCondition = beginConversationCondition;
}
public ValueExpression<Boolean> getEndConversationCondition()
{
return endConversationCondition;
}
public void setEndConversationCondition(ValueExpression<Boolean> endConversationCondition)
{
this.endConversationCondition = endConversationCondition;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/ConversationIdParameter.java
Index: ConversationIdParameter.java
===================================================================
package org.jboss.seam.navigation;
import java.util.Map;
public interface ConversationIdParameter
{
String getName();
String getParameterName();
String getParameterValue();
String getConversationId();
String getInitialConversationId(Map parameters);
String getRequestConversationId(Map parameters);
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/ELConversationIdParameter.java
Index: ELConversationIdParameter.java
===================================================================
package org.jboss.seam.navigation;
import java.util.Map;
import org.jboss.seam.core.ConversationPropagation;
import org.jboss.seam.core.Expressions;
import org.jboss.seam.core.Expressions.ValueExpression;
import org.jboss.seam.util.Id;
/**
* Represents a conversation parameter that can be used to create a "natural"
* conversation ID, by defining a <conversation/> entry in pages.xml.
*
* @author Shane Bryzak
*/
public class ELConversationIdParameter implements ConversationIdParameter
{
private String name;
private String parameterName;
private ValueExpression vb;
public ELConversationIdParameter(String name, String paramName, String expression)
{
this.name = name;
this.parameterName = paramName;
this.vb = expression != null ?
Expressions.instance().createValueExpression(expression) : null;
}
public String getName()
{
return name;
}
public String getParameterName()
{
return parameterName;
}
public String getInitialConversationId(Map parameters)
{
String id = getRequestConversationId(parameters);
return id==null ? Id.nextId() : id; //TODO: should we try using the expression?
}
public String getRequestConversationId(Map parameters)
{
String value = ConversationPropagation.getRequestParameterValue(parameters, parameterName);
if (value==null)
{
return null;
}
else
{
return name + ':' + value;
}
}
public String getConversationId()
{
return name + ':' + getParameterValue();
}
public String getParameterValue()
{
Object value = vb.getValue();
if (value==null)
{
throw new IllegalStateException("conversation id evaluated to null: " + name);
}
else
{
//TODO: use a JSF converter!
return vb.getValue().toString();
}
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Input.java
Index: Input.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.Component;
public class Input extends Put
{
public void in()
{
Object object = getScope()==null ?
Component.getInstance( getName() ) :
getScope().getContext().get( getName() );
getValue().setValue( object );
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Navigation.java
Index: Navigation.java
===================================================================
package org.jboss.seam.navigation;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import org.jboss.seam.core.Expressions.ValueExpression;
public final class Navigation
{
private ValueExpression<Object> outcome;
private List<Rule> rules = new ArrayList<Rule>();
private Rule rule;
public List<Rule> getRules()
{
return rules;
}
public void setOutcome(ValueExpression<Object> outcomeValueExpression)
{
this.outcome = outcomeValueExpression;
}
public ValueExpression<Object> getOutcome()
{
return outcome;
}
public Rule getRule()
{
return rule;
}
public void setRule(Rule rule)
{
this.rule = rule;
}
public boolean navigate(FacesContext context, final String actionOutcomeValue)
{
String outcomeValue;
if ( getOutcome()==null )
{
outcomeValue = actionOutcomeValue;
}
else
{
Object value = getOutcome().getValue();
outcomeValue = value==null ? null : value.toString();
}
for ( Rule rule: getRules() )
{
if ( rule.matches(outcomeValue) )
{
return rule.execute(context);
}
}
return getRule().execute(context);
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/NavigationHandler.java
Index: NavigationHandler.java
===================================================================
package org.jboss.seam.navigation;
import javax.faces.context.FacesContext;
import org.jboss.seam.faces.Navigator;
public abstract class NavigationHandler extends Navigator
{
public abstract boolean navigate(FacesContext context);
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Output.java
Index: Output.java
===================================================================
package org.jboss.seam.navigation;
public class Output extends Put
{
public void out()
{
getScope().getContext().set( getName(), getValue().getValue() );
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Page.java
Index: Page.java
===================================================================
package org.jboss.seam.navigation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import javax.faces.context.FacesContext;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Interpolator;
import org.jboss.seam.international.Locale;
import org.jboss.seam.security.Identity;
/**
* Metadata about page actions, page parameters, action navigation,
* resource bundle, etc, for a particular JSF view id.
*/
public final class Page
{
private final String viewId;
private String description;
private Integer timeout;
private String noConversationViewId;
private String resourceBundleName;
private boolean switchEnabled = true;
private List<Param> parameters = new ArrayList<Param>();
private List<Input> inputs = new ArrayList<Input>();
private List<Action> actions = new ArrayList<Action>();
private Map<String, Navigation> navigations = new HashMap<String, Navigation>();
private Navigation defaultNavigation;
private boolean conversationRequired;
private boolean loginRequired;
private ConversationControl conversationControl = new ConversationControl();
private TaskControl taskControl = new TaskControl();
private ProcessControl processControl = new ProcessControl();
private ConversationIdParameter conversationIdParameter;
private String eventType;
/**
* The scheme (http/https) required by this page.
*/
private String scheme;
/**
* Indicates whether this view id has a security restriction.
*/
private boolean restricted;
/**
* A security restriction expression to evaluate when requesting this view id.
* If the view is restricted but no restriction expression is set, the implied
* permission restriction will be name="[viewid]", action="[get or post]"
*/
private String restriction;
public Page(String viewId)
{
this.viewId = viewId;
if (viewId!=null)
{
int loc = viewId.lastIndexOf('.');
if ( loc>0 && viewId.startsWith("/") )
{
this.setResourceBundleName( viewId.substring(1, loc) );
}
}
conversationIdParameter = new SyntheticConversationIdParameter();
}
public java.util.ResourceBundle getResourceBundle()
{
String resourceBundleName = getResourceBundleName();
if (resourceBundleName==null)
{
return null;
}
else
{
try
{
return java.util.ResourceBundle.getBundle(
resourceBundleName,
Locale.instance(),
Thread.currentThread().getContextClassLoader()
);
}
catch (MissingResourceException mre)
{
return null;
}
}
}
@Override
public String toString()
{
return "Page(" + getViewId() + ")";
}
public String getViewId()
{
return viewId;
}
public String renderDescription()
{
return Interpolator.instance().interpolate( getDescription() );
}
public void setDescription(String description)
{
this.description = description;
}
public String getDescription()
{
return description;
}
public void setTimeout(Integer timeout)
{
this.timeout = timeout;
}
public Integer getTimeout()
{
return timeout;
}
public void setNoConversationViewId(String noConversationViewId)
{
this.noConversationViewId = noConversationViewId;
}
public String getNoConversationViewId()
{
return noConversationViewId;
}
public void setResourceBundleName(String resourceBundleName)
{
this.resourceBundleName = resourceBundleName;
}
public String getResourceBundleName()
{
return resourceBundleName;
}
public void setSwitchEnabled(boolean switchEnabled)
{
this.switchEnabled = switchEnabled;
}
public boolean isSwitchEnabled()
{
return switchEnabled;
}
public List<Param> getParameters()
{
return parameters;
}
public Map<String, Navigation> getNavigations()
{
return navigations;
}
public boolean hasDescription()
{
return description!=null;
}
public boolean isConversationRequired()
{
return conversationRequired;
}
public void setConversationRequired(boolean conversationRequired)
{
this.conversationRequired = conversationRequired;
}
public Navigation getDefaultNavigation()
{
return defaultNavigation;
}
public void setDefaultNavigation(Navigation defaultActionOutcomeMapping)
{
this.defaultNavigation = defaultActionOutcomeMapping;
}
public ConversationControl getConversationControl()
{
return conversationControl;
}
public TaskControl getTaskControl()
{
return taskControl;
}
public ProcessControl getProcessControl()
{
return processControl;
}
public List<Action> getActions()
{
return actions;
}
private void checkPermission(FacesContext facesContext, String name)
{
if ( isRestricted() && Identity.isSecurityEnabled() )
{
// If no expression is configured, create a default one
if (restriction == null)
{
Identity.instance().checkPermission( Pages.getViewId(facesContext), name );
}
else
{
Identity.instance().checkRestriction(restriction);
}
}
}
/**
* Check the restore permission.
*/
public void postRestore(FacesContext facesContext)
{
checkPermission(facesContext, "restore");
}
/**
* Call page actions, in order they appear in XML, and
* handle conversation begin/end. Also check the
* render permission.
*/
public boolean preRender(FacesContext facesContext)
{
checkPermission(facesContext, "render");
boolean result = false;
getConversationControl().beginOrEndConversation();
getTaskControl().beginOrEndTask();
getProcessControl().createOrResumeProcess();
for ( Input in: getInputs() ) in.in();
if (eventType!=null)
{
Events.instance().raiseEvent(eventType);
}
for ( Action action: getActions() )
{
if ( action.isExecutable() )
{
String outcome = action.getOutcome();
String fromAction = outcome;
if (outcome==null)
{
fromAction = action.getMethodExpression().getExpressionString();
result = true;
outcome = Pages.toString( action.getMethodExpression().invoke() );
Pages.handleOutcome(facesContext, outcome, fromAction);
}
else
{
Pages.handleOutcome(facesContext, outcome, fromAction);
}
}
}
return result;
}
public List<Input> getInputs()
{
return inputs;
}
public boolean isRestricted()
{
return restricted;
}
public void setRestricted(boolean restricted)
{
this.restricted = restricted;
}
public String getRestriction()
{
return restriction;
}
public void setRestriction(String restriction)
{
this.restriction = restriction;
}
public boolean isLoginRequired()
{
return loginRequired;
}
public void setLoginRequired(boolean loginRequired)
{
this.loginRequired = loginRequired;
}
public String getScheme()
{
return scheme;
}
public void setScheme(String scheme)
{
this.scheme = scheme;
}
public ConversationIdParameter getConversationIdParameter()
{
return conversationIdParameter;
}
public void setConversationIdParameter(ConversationIdParameter param)
{
this.conversationIdParameter = param;
}
public String getEventType()
{
return eventType;
}
public void setEventType(String eventType)
{
this.eventType = eventType;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Pageflow.java
Index: Pageflow.java
===================================================================
package org.jboss.seam.navigation;
import static org.jboss.seam.InterceptionType.NEVER;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.Serializable;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Intercept;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.PerNestedConversation;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.bpm.Jbpm;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.core.AbstractMutable;
import org.jboss.seam.core.Events;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.faces.FacesPage;
import org.jboss.seam.faces.JsfManager;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.pageflow.Page;
import org.jboss.seam.pageflow.PageflowHelper;
import org.jbpm.graph.def.Action;
import org.jbpm.graph.def.Event;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.exe.ProcessInstance;
/**
* A Seam component that manages the current
* jBPM ProcessInstance used for pageflow.
*
* @author Gavin King
*/
@Scope(ScopeType.CONVERSATION)
@PerNestedConversation
@Name("org.jboss.seam.core.pageflow")
@Intercept(NEVER)
@Install(dependencies="org.jboss.seam.core.jbpm", precedence=BUILT_IN)
public class Pageflow extends AbstractMutable implements Serializable
{
private static final long serialVersionUID = -2337682140346213333L;
private static final LogProvider log = Logging.getLogProvider(Pageflow.class);
private int counter;
private ProcessInstance processInstance;
public boolean isInProcess()
{
return processInstance!=null;
}
public ProcessInstance getProcessInstance()
{
return processInstance;
}
public void setProcessInstance(ProcessInstance processInstance)
{
this.processInstance = processInstance;
setDirty();
}
public static Pageflow instance()
{
if ( !Contexts.isConversationContextActive() )
{
throw new IllegalStateException("No active conversation context");
}
return (Pageflow) Component.getInstance(Pageflow.class, ScopeType.CONVERSATION);
}
/**
* Get the current counter value, used for detecting
* illegal use of the backbutton.
*/
public int getPageflowCounter()
{
return counter;
}
/**
* Check that the current state of the pageflow matches
* what is expected by the faces request.
*/
public void validatePageflow()
{
if ( processInstance!=null )
{
org.jboss.seam.faces.FacesPage page = org.jboss.seam.faces.FacesPage.instance();
String pageflowName = page.getPageflowName();
String pageflowNodeName = page.getPageflowNodeName();
boolean canReposition = getPage().isBackEnabled() &&
getSubProcessInstance().getProcessDefinition().getName().equals(pageflowName) && //probably not necessary
pageflowNodeName!=null; //probably not necessary
if (canReposition)
{
//check the node name to make sure we are still on the same node
if ( !pageflowNodeName.equals( getNode().getName() ) )
{
//legal use of back/forward button, so reposition
reposition(pageflowNodeName);
}
}
else
{
//check the counter to detect illegal use of backbutton
Integer pageCounter = org.jboss.seam.faces.FacesPage.instance().getPageflowCounter();
if ( pageCounter!=null && getPageflowCounter()!=pageCounter )
{
illegalNavigationError();
}
}
}
}
private void illegalNavigationError()
{
FacesContext context = FacesContext.getCurrentInstance();
navigate(context);
illegalNavigation();
context.renderResponse();
}
/**
* Add a message to indicate that illegal navigation
* occurred. May be overridden by user to perform
* special processing.
*/
protected void illegalNavigation()
{
FacesMessages.instance().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_WARN,
"org.jboss.seam.IllegalNavigation",
"Illegal navigation"
);
}
/**
* Get the current Node of the pageflow.
*/
public Node getNode()
{
if (processInstance==null) return null;
Node node = getSubProcessInstance().getRootToken().getNode();
if (node==null)
{
throw new IllegalStateException("pageflow has not yet started");
}
return node;
}
public ProcessInstance getSubProcessInstance()
{
return getSubProcess(processInstance);
}
private static ProcessInstance getSubProcess(ProcessInstance processInstance)
{
ProcessInstance subProcess = processInstance.getRootToken().getSubProcessInstance();
if (subProcess!=null)
{
return getSubProcess(subProcess);
}
else
{
return processInstance;
}
}
/**
* Reposition the pageflow at the named node.
*
* @param nodeName the name of a node
*/
public void reposition(String nodeName)
{
if (processInstance==null)
{
throw new IllegalStateException("no pageflow in progress");
}
ProcessInstance subProcess = getSubProcessInstance();
Node node = subProcess.getProcessDefinition().getNode(nodeName);
if (node==null)
{
throw new IllegalArgumentException(
"no node named: " + nodeName +
" for pageflow: " + subProcess.getProcessDefinition().getName()
);
}
subProcess.getRootToken().setNode(node);
setDirty();
}
/**
* Get the current Page of the pageflow.
*/
public Page getPage()
{
Node node = getNode();
if ( node!=null && !(node instanceof Page) )
{
throw new IllegalStateException("pageflow is not currently at a <page> or <start-page> node (note that pageflows that begin during the RENDER_RESPONSE phase should use <start-page> instead of <start-state>)");
}
return (Page) node;
}
/**
* Navigate to the current page.
*/
protected void navigate(FacesContext context)
{
Page page = getPage();
if ( !page.isRedirect() )
{
render(context, page);
}
else
{
redirect(page);
}
counter++;
setDirty();
}
/**
* Redirect to the Page.
*/
protected void redirect(Page page)
{
JsfManager.instance().redirect( getViewId(page) );
}
/**
* Proceed to render the Page.
*/
protected void render(FacesContext context, Page page)
{
UIViewRoot viewRoot = context.getApplication().getViewHandler()
.createView( context, getViewId(page) );
context.setViewRoot(viewRoot);
}
/**
* Allows the user to extend this class and use some
* logical naming of pages other than the JSF view id
* in their pageflow.
*
* @param page the Page object
* @return a JSF view id
*/
protected String getViewId(Page page)
{
return page.getViewId();
}
/**
* Get the JSF view id of the current page in the
* pageflow.
*/
public String getPageViewId()
{
Page page = getPage();
return page==null ? null : getViewId(page);
}
/**
* Does the current node have a default transition?
*/
public boolean hasDefaultTransition()
{
//we don't use jBPM's default transition,
//instead we use the "anonymous" transition
return getNode().getLeavingTransition(null)!=null;
}
private boolean isNullOutcome(String outcome)
{
return outcome==null || "".equals(outcome);
}
public boolean hasTransition(String outcome)
{
return isNullOutcome(outcome) ?
hasDefaultTransition() :
getNode().getLeavingTransition(outcome)!=null;
}
/**
* Given the JSF action outcome, perform navigation according
* to the current pageflow.
*/
public void navigate(FacesContext context, String outcome)
{
ProcessInstance subProcess = getSubProcessInstance();
if ( isNullOutcome(outcome) )
{
//if it has a default transition defined, trigger it,
//otherwise just redisplay the page
if ( hasDefaultTransition() )
{
//we don't use jBPM's default transition,
//instead we use the "anonymous" transition
PageflowHelper.signal(subProcess, null);
navigate(context);
}
}
else
{
//trigger the named transition
PageflowHelper.signal(subProcess, outcome);
navigate(context);
}
raiseEndEventIfNecessary();
}
protected void raiseEndEventIfNecessary()
{
if ( processInstance.hasEnded() )
{
Events.instance().raiseEvent(
"org.jboss.seam.endPageflow." +
processInstance.getProcessDefinition().getName()
);
}
}
/**
* Process events defined in the pageflow.
*
* @param type one of: "process-validations", "update-model-values",
* "invoke-application", "render-response"
*/
public void processEvents(String type)
{
Event event = getNode().getEvent(type);
if (event!=null)
{
for ( Action action: (List<Action>) event.getActions() )
{
try
{
action.execute( ExecutionContext.currentExecutionContext() );
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}
/**
* Begin executing a pageflow.
*
* @param pageflowDefinitionName the name of the pageflow definition
*/
public void begin(String pageflowDefinitionName)
{
if ( log.isDebugEnabled() )
{
log.debug("beginning pageflow: " + pageflowDefinitionName);
}
processInstance = PageflowHelper.newPageflowInstance( getPageflowProcessDefinition(pageflowDefinitionName) );
//if ( Lifecycle.getPhaseId().equals(PhaseId.RENDER_RESPONSE) )
//{
//if a pageflow starts during the render response phase
//(as a result of a @Create method), we know the navigation
//handler will not get called, so we should force the
//pageflow out of the start state immediately
//TODO: this is not actually completely true, what about <s:actionLink/>
//pi.signal();
//}
setDirty();
raiseBeginEvent(pageflowDefinitionName);
storePageflowToViewRootIfNecessary();
}
protected void raiseBeginEvent(String pageflowDefinitionName)
{
Events.instance().raiseEvent("org.jboss.seam.beginPageflow." + pageflowDefinitionName);
}
private void storePageflowToViewRootIfNecessary()
{
FacesContext facesContext = FacesContext.getCurrentInstance();
if ( facesContext!=null && Lifecycle.getPhaseId()==PhaseId.RENDER_RESPONSE )
{
FacesPage.instance().storePageflow();
}
}
public String getNoConversationViewId(String pageflowName, String pageflowNodeName)
{
ProcessDefinition pageflowProcessDefinition = getPageflowProcessDefinition(pageflowName);
Node node = pageflowProcessDefinition.getNode(pageflowNodeName);
if (node!=null && node instanceof Page)
{
return ( (Page) node ).getNoConversationViewId();
}
else
{
return null;
}
}
protected ProcessDefinition getPageflowProcessDefinition(String pageflowName)
{
ProcessDefinition pageflowProcessDefinition = Jbpm.instance().getPageflowProcessDefinition(pageflowName);
if (pageflowProcessDefinition==null)
{
throw new IllegalArgumentException("pageflow definition not found: " + pageflowName);
}
return pageflowProcessDefinition;
}
@Override
public String toString()
{
String name = processInstance==null ?
"null" : processInstance.getProcessDefinition().getName();
return "Pageflow(" + name + ")";
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Pages.java
Index: Pages.java
===================================================================
package org.jboss.seam.navigation;
import static org.jboss.seam.InterceptionType.NEVER;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;
import javax.faces.model.DataModel;
import javax.faces.validator.ValidatorException;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.FlushModeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Intercept;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Expressions;
import org.jboss.seam.core.Init;
import org.jboss.seam.core.Manager;
import org.jboss.seam.core.Expressions.MethodExpression;
import org.jboss.seam.core.Expressions.ValueExpression;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.faces.Validation;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.security.Identity;
import org.jboss.seam.security.NotLoggedInException;
import org.jboss.seam.util.Resources;
import org.jboss.seam.util.Strings;
import org.jboss.seam.util.XML;
import org.jboss.seam.web.Parameters;
/**
* Holds metadata for pages defined in pages.xml, including
* page actions and page descriptions.
*
* @author Gavin King
*/
@Scope(ScopeType.APPLICATION)
@Intercept(NEVER)
@Name("org.jboss.seam.core.pages")
@Install(precedence=BUILT_IN)
public class Pages
{
private static final LogProvider log = Logging.getLogProvider(Pages.class);
private Map<String, Page> pagesByViewId = Collections.synchronizedMap( new HashMap<String, Page>() );
private Map<String, List<Page>> pageStacksByViewId = Collections.synchronizedMap( new HashMap<String, List<Page>>() );
private String noConversationViewId;
private String loginViewId;
private Map<String, ConversationIdParameter> conversations = Collections.synchronizedMap( new HashMap<String, ConversationIdParameter>() );
private Integer httpPort;
private Integer httpsPort;
private String[] resources = { "/WEB-INF/pages.xml" };
private SortedSet<String> wildcardViewIds = new TreeSet<String>(
new Comparator<String>()
{
public int compare(String x, String y)
{
if ( x.length()<y.length() ) return -1;
if ( x.length()> y.length() ) return 1;
return x.compareTo(y);
}
}
);
@Create
public void initialize()
{
for (String resource: resources)
{
InputStream stream = Resources.getResourceAsStream(resource);
if (stream==null)
{
log.info("no pages.xml file found: " + resource);
}
else
{
log.debug("reading pages.xml file: " + resource);
parse(stream);
}
}
}
/**
* Run any navigation rule defined in pages.xml
*
* @param actionExpression the action method binding expression
* @param actionOutcomeValue the outcome of the action method
* @return true if a navigation rule was found
*/
public boolean navigate(FacesContext context, String actionExpression, String actionOutcomeValue)
{
String viewId = getViewId(context);
if (viewId!=null)
{
List<Page> stack = getPageStack(viewId);
for (int i=stack.size()-1; i>=0; i--)
{
Page page = stack.get(i);
Navigation navigation = page.getNavigations().get(actionExpression);
if (navigation==null)
{
navigation = page.getDefaultNavigation();
}
if ( navigation!=null && navigation.navigate(context, actionOutcomeValue) ) return true;
}
}
return false;
}
/**
* Get the Page object for the given view id.
*
* @param viewId a JSF view id
*/
public Page getPage(String viewId)
{
if (viewId==null)
{
//for tests
return new Page(viewId);
}
else
{
Page result = getCachedPage(viewId);
if (result==null)
{
return createPage(viewId);
}
else
{
return result;
}
}
}
/**
* Create a new Page object for a JSF view id,
* by searching for a viewId.page.xml file.
*/
private Page createPage(String viewId)
{
String resourceName = replaceExtension(viewId, ".page.xml");
InputStream stream = resourceName==null ?
null : Resources.getResourceAsStream( resourceName.substring(1) );
if ( stream==null )
{
Page result = new Page(viewId);
pagesByViewId.put(viewId, result);
return result;
}
else
{
parse(stream, viewId);
return getCachedPage(viewId);
}
}
private Page getCachedPage(String viewId)
{
Page result = pagesByViewId.get(viewId);
if (result==null)
{
//workaround for what I believe is a bug in the JSF RI
viewId = replaceExtension( viewId, getSuffix() );
if (viewId!=null)
{
result = pagesByViewId.get(viewId);
}
}
return result;
}
private static String replaceExtension(String viewId, String suffix)
{
int loc = viewId.lastIndexOf('.');
return loc<0 ? null : viewId.substring(0, loc) + suffix;
}
/**
* Get the stack of Page objects, from least specific to
* most specific, that match the given view id.
*
* @param viewId a JSF view id
*/
protected List<Page> getPageStack(String viewId)
{
List<Page> stack = pageStacksByViewId.get(viewId);
if (stack==null)
{
stack = createPageStack(viewId);
pageStacksByViewId.put(viewId, stack);
}
return stack;
}
/**
* Create the stack of pages that match a JSF view id
*/
private List<Page> createPageStack(String viewId)
{
List<Page> stack = new ArrayList<Page>(1);
if (viewId!=null)
{
for (String wildcard: wildcardViewIds)
{
if ( viewId.startsWith( wildcard.substring(0, wildcard.length()-1) ) )
{
stack.add( getPage(wildcard) );
}
}
}
Page page = getPage(viewId);
if (page!=null) stack.add(page);
return stack;
}
/**
* Call page actions, check permissions and validate the existence
* of a conversation for pages which require a long-running
* conversation, starting with the most general view id, ending at
* the most specific. Also perform redirection to the required
* scheme if necessary.
*/
public boolean preRender(FacesContext facesContext)
{
String viewId = getViewId(facesContext);
//redirect to HTTPS if necessary
String requestScheme = getRequestScheme(facesContext);
if ( requestScheme!=null )
{
String scheme = getScheme(viewId);
if ( scheme!=null && !requestScheme.equals(scheme) )
{
Manager.instance().redirect(viewId);
return false;
}
}
//apply the datamodelselection passed by s:link or s:button
//before running any actions
selectDataModelRow(facesContext);
//redirect if necessary
List<Page> pageStack = getPageStack(viewId);
for ( Page page: pageStack )
{
if ( isNoConversationRedirectRequired(page) )
{
redirectToNoConversationView();
return false;
}
else if ( isLoginRedirectRequired(viewId, page) )
{
redirectToLoginView();
return false;
}
}
//run the page actions, check permissions,
//handle conversation begin/end
boolean result = false;
for ( Page page: pageStack )
{
result = page.preRender(facesContext) || result;
}
//run the s:link / s:button action after checking the
//conversation existence!
result = callAction(facesContext) || result;
return result;
}
/**
* Look for a DataModel row selection in the request parameters,
* and apply it to the DataModel.
*
* @param parameters the request parameters
*/
private void selectDataModelRow(FacesContext facesContext)
{
String dataModelSelection = facesContext.getExternalContext()
.getRequestParameterMap().get("dataModelSelection");
if (dataModelSelection!=null)
{
int colonLoc = dataModelSelection.indexOf(':');
int bracketLoc = dataModelSelection.indexOf('[');
if (colonLoc>0 && bracketLoc>colonLoc)
{
String var = dataModelSelection.substring(0, colonLoc);
String name = dataModelSelection.substring(colonLoc+1, bracketLoc);
int index = Integer.parseInt( dataModelSelection.substring( bracketLoc+1, dataModelSelection.length()-1 ) );
Object value = Contexts.lookupInStatefulContexts(name);
if (value!=null)
{
DataModel dataModel = (DataModel) value;
if ( index<dataModel.getRowCount() )
{
dataModel.setRowIndex(index);
Contexts.getEventContext().set( var, dataModel.getRowData() );
}
else
{
log.warn("DataModel row was unavailable");
Contexts.getEventContext().remove(var);
}
}
}
}
}
/**
* Check permissions and validate the existence of a conversation
* for pages which require a long-running conversation, starting
* with the most general view id, ending at the most specific.
* Finally apply page parameters to the model.
*/
public void postRestore(FacesContext facesContext)
{
//first store the page parameters into the viewroot, so
//that if a login redirect occurs, or if a failure
//occurs while applying to the model, we can still make
//Redirect.captureCurrentView() work.
boolean validationFailed = storeRequestParameterValuesInViewRoot(facesContext);
if (validationFailed) Validation.instance().fail();
String viewId = getViewId(facesContext);
for ( Page page: getPageStack(viewId) )
{
if ( isLoginRedirectRequired(viewId, page) )
{
redirectToLoginView();
return;
}
else if ( isNoConversationRedirectRequired(page) )
{
redirectToNoConversationView();
return;
}
else
{
//if we are about to proceed to the action
//phase, check the permission.
if ( !facesContext.getRenderResponse() )
{
page.postRestore(facesContext);
}
}
}
//now apply page parameters to the model
//(after checking permissions)
applyViewRootValues(facesContext);
}
private boolean isNoConversationRedirectRequired(Page page)
{
return page.isConversationRequired() &&
!Manager.instance().isLongRunningOrNestedConversation();
}
private boolean isLoginRedirectRequired(String viewId, Page page)
{
return page.isLoginRequired() &&
!viewId.equals( getLoginViewId() ) &&
!Identity.instance().isLoggedIn();
}
public static String getRequestScheme(FacesContext facesContext)
{
String requestUrl = getRequestUrl(facesContext);
if (requestUrl==null)
{
return null;
}
else
{
int idx = requestUrl.indexOf(':');
return idx<0 ? null : requestUrl.substring(0, idx);
}
}
public String encodeScheme(String viewId, FacesContext context, String url)
{
String scheme = getScheme(viewId);
if (scheme != null)
{
String requestUrl = getRequestUrl(context);
if (requestUrl!=null)
{
try
{
URL serverUrl = new URL(requestUrl);
StringBuilder sb = new StringBuilder();
sb.append(scheme);
sb.append("://");
sb.append(serverUrl.getHost());
if ("http".equals(scheme) && httpPort != null)
{
sb.append(":");
sb.append(httpPort);
}
else if ("https".equals(scheme) && httpsPort != null)
{
sb.append(":");
sb.append(httpsPort);
}
else if (serverUrl.getPort() != -1)
{
sb.append(":");
sb.append(serverUrl.getPort());
}
if (!url.startsWith("/")) sb.append("/");
sb.append(url);
url = sb.toString();
}
catch (MalformedURLException ex)
{
throw new RuntimeException(ex);
}
}
}
return url;
}
private static String getRequestUrl(FacesContext facesContext)
{
Object request = facesContext.getExternalContext().getRequest();
if (request instanceof HttpServletRequest)
{
return ( (HttpServletRequest) request).getRequestURL().toString();
}
else
{
return null;
}
}
public void redirectToLoginView()
{
notLoggedIn();
String loginViewId = getLoginViewId();
if (loginViewId==null)
{
throw new NotLoggedInException();
}
else
{
Manager.instance().redirect(loginViewId);
}
}
public void redirectToNoConversationView()
{
noConversation();
//stuff from jPDL takes precedence
org.jboss.seam.faces.FacesPage facesPage = org.jboss.seam.faces.FacesPage.instance();
String pageflowName = facesPage.getPageflowName();
String pageflowNodeName = facesPage.getPageflowNodeName();
String noConversationViewId = null;
if (pageflowName==null || pageflowNodeName==null)
{
String viewId = Pages.getCurrentViewId();
noConversationViewId = getNoConversationViewId(viewId);
}
else
{
noConversationViewId = Pageflow.instance().getNoConversationViewId(pageflowName, pageflowNodeName);
}
if (noConversationViewId!=null)
{
Manager.instance().redirect(noConversationViewId);
}
}
public String getScheme(String viewId)
{
List<Page> stack = getPageStack(viewId);
for ( int i = stack.size() - 1; i >= 0; i-- )
{
Page page = stack.get(i);
if (page.getScheme() != null) return page.getScheme();
}
return null;
}
protected void noConversation()
{
Events.instance().raiseEvent("org.jboss.seam.noConversation");
FacesMessages.instance().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_WARN,
"org.jboss.seam.NoConversation",
"The conversation ended, timed out or was processing another request"
);
}
protected void notLoggedIn()
{
Events.instance().raiseEvent("org.jboss.seam.notLoggedIn");
FacesMessages.instance().addFromResourceBundleOrDefault(
FacesMessage.SEVERITY_WARN,
"org.jboss.seam.NotLoggedIn",
"Please log in first"
);
}
public static String toString(Object returnValue)
{
return returnValue == null ? null : returnValue.toString();
}
/**
* Call the JSF navigation handler
*/
public static void handleOutcome(FacesContext facesContext, String outcome, String fromAction)
{
facesContext.getApplication().getNavigationHandler()
.handleNavigation(facesContext, fromAction, outcome);
//after every time that the view may have changed,
//we need to flush the page context, since the
//attribute map is being discarder
Contexts.getPageContext().flush();
}
public static Pages instance()
{
if ( !Contexts.isApplicationContextActive() )
{
throw new IllegalStateException("No active application context");
}
return (Pages) Component.getInstance(Pages.class, ScopeType.APPLICATION);
}
/**
* Call the action requested by s:link or s:button.
*/
private static boolean callAction(FacesContext facesContext)
{
//TODO: refactor with Pages.instance().callAction()!!
boolean result = false;
String outcome = facesContext.getExternalContext()
.getRequestParameterMap().get("actionOutcome");
String fromAction = outcome;
if (outcome==null)
{
String actionId = facesContext.getExternalContext()
.getRequestParameterMap().get("actionMethod");
if (actionId!=null)
{
if ( !SafeActions.instance().isActionSafe(actionId) ) return result;
String expression = SafeActions.toAction(actionId);
result = true;
MethodExpression actionExpression = Expressions.instance().createMethodExpression(expression);
outcome = toString( actionExpression.invoke() );
fromAction = expression;
handleOutcome(facesContext, outcome, fromAction);
}
}
else
{
handleOutcome(facesContext, outcome, fromAction);
}
return result;
}
/**
* Build a list of page-scoped resource bundles, from most
* specific view id, to most general.
*/
public List<ResourceBundle> getResourceBundles(String viewId)
{
List<ResourceBundle> result = new ArrayList<ResourceBundle>(1);
List<Page> stack = getPageStack(viewId);
for (int i=stack.size()-1; i>=0; i--)
{
Page page = stack.get(i);
ResourceBundle bundle = page.getResourceBundle();
if ( bundle!=null ) result.add(bundle);
}
return result;
}
/**
* Get the values of any page parameters by evaluating the value bindings
* against the model and converting to String.
*
* @param viewId the JSF view id
* @return a map of page parameter name to String value
*/
public Map<String, Object> getConvertedParameters(FacesContext facesContext, String viewId)
{
return getConvertedParameters(facesContext, viewId, Collections.EMPTY_SET);
}
/**
* Get the values of any page parameters by evaluating the value bindings
* against the model.
*
* @param viewId the JSF view id
* @return a map of page parameter name to value
*/
protected Map<String, Object> getParameters(String viewId)
{
Map<String, Object> parameters = new HashMap<String, Object>();
for ( Page page: getPageStack(viewId) )
{
for ( Param pageParameter: page.getParameters() )
{
ValueExpression valueExpression = pageParameter.getValueExpression();
Object value;
if (valueExpression==null)
{
value = Contexts.getPageContext().get( pageParameter.getName() );
}
else
{
value = valueExpression.getValue();
}
if (value!=null)
{
parameters.put( pageParameter.getName(), value );
}
}
}
return parameters;
}
/**
* Get the values of any page parameters by evaluating the value bindings
* against the model and converting to String.
*
* @param viewId the JSF view id
* @param overridden excluded parameters
* @return a map of page parameter name to String value
*/
public Map<String, Object> getConvertedParameters(FacesContext facesContext, String viewId, Set<String> overridden)
{
Map<String, Object> parameters = new HashMap<String, Object>();
for ( Page page: getPageStack(viewId) )
{
for ( Param pageParameter: page.getParameters() )
{
if ( !overridden.contains( pageParameter.getName() ) )
{
Object value = getPageParameterValue(facesContext, pageParameter);
if (value!=null)
{
parameters.put( pageParameter.getName(), value );
}
}
}
}
return parameters;
}
/**
* Get the current value of a page parameter, looking in the page context
* if there is no value binding
*/
private Object getPageParameterValue(FacesContext facesContext, Param pageParameter)
{
ValueExpression valueExpression = pageParameter.getValueExpression();
if (valueExpression==null)
{
return Contexts.getPageContext().get( pageParameter.getName() );
}
else
{
return pageParameter.getValueFromModel(facesContext);
}
}
private boolean storeRequestParameterValuesInViewRoot(FacesContext facesContext)
{
String viewId = getViewId(facesContext);
Map<String, String[]> requestParameters = Parameters.instance().getRequestParameters();
boolean validationFailed = false;
for ( Page page: getPageStack(viewId) )
{
for ( Param pageParameter: page.getParameters() )
{
try
{
Object value = pageParameter.getValueFromRequest(facesContext, requestParameters);
if (value==null)
{
if ( facesContext.getRenderResponse() ) //ie. for a non-faces request
{
//this should not be necessary, were it not for a MyFaces bug
Contexts.getPageContext().remove( pageParameter.getName() );
}
//TODO: add some support for required=true
}
else
{
Contexts.getPageContext().set( pageParameter.getName(), value );
}
}
catch (ValidatorException ve)
{
facesContext.addMessage( null, ve.getFacesMessage() );
validationFailed = true;
}
catch (ConverterException ce)
{
facesContext.addMessage( null, ce.getFacesMessage() );
validationFailed = true;
}
}
}
return validationFailed;
}
/**
* Apply any page parameters passed as view root attributes to the model.
*/
private void applyViewRootValues(FacesContext facesContext)
{
String viewId = getViewId(facesContext);
for ( Page page: getPageStack(viewId) )
{
for ( Param pageParameter: page.getParameters() )
{
ValueExpression valueExpression = pageParameter.getValueExpression();
if (valueExpression!=null)
{
Object object = Contexts.getPageContext().get( pageParameter.getName() );
if (object!=null)
{
valueExpression.setValue(object);
}
}
}
}
}
public Map<String, Object> getViewRootValues(FacesContext facesContext)
{
Map<String, Object> parameters = new HashMap<String, Object>();
String viewId = getViewId(facesContext);
for ( Page page: getPageStack(viewId) )
{
for ( Param pageParameter: page.getParameters() )
{
Object object = Contexts.getPageContext().get( pageParameter.getName() );
if (object!=null)
{
parameters.put( pageParameter.getName(), object );
}
}
}
return parameters;
}
/**
* The global setting for no-conversation-viewid.
*
* @return a JSF view id
*/
public String getNoConversationViewId()
{
return noConversationViewId;
}
public void setNoConversationViewId(String noConversationViewId)
{
this.noConversationViewId = noConversationViewId;
}
/**
* Encode page parameters into a URL
*
* @param url the base URL
* @param viewId the JSF view id of the page
* @return the URL with parameters appended
*/
public String encodePageParameters(FacesContext facesContext, String url, String viewId)
{
return encodePageParameters(facesContext, url, viewId, Collections.EMPTY_SET);
}
/**
* Encode page parameters into a URL
*
* @param url the base URL
* @param viewId the JSF view id of the page
* @param overridden excluded parameters
* @return the URL with parameters appended
*/
public String encodePageParameters(FacesContext facesContext, String url, String viewId, Set<String> overridden)
{
Map<String, Object> parameters = getConvertedParameters(facesContext, viewId, overridden);
return Manager.instance().encodeParameters(url, parameters);
}
/**
* Store the page parameters to the JSF view root
*/
public void storePageParameters(FacesContext facesContext)
{
String viewId = getViewId(facesContext);
for ( Map.Entry<String, Object> param: getParameters(viewId).entrySet() )
{
Contexts.getPageContext().set( param.getKey(), param.getValue() );
}
}
/**
* Search for a defined no-conversation-view-id, beginning with
* the most specific view id, then wildcarded view ids, and
* finally the global setting
*/
public String getNoConversationViewId(String viewId)
{
List<Page> stack = getPageStack(viewId);
for (int i=stack.size()-1; i>=0; i--)
{
Page page = stack.get(i);
String noConversationViewId = page.getNoConversationViewId();
if (noConversationViewId!=null)
{
return noConversationViewId;
}
}
return this.noConversationViewId;
}
/**
* Search for a defined conversation timeout, beginning with
* the most specific view id, then wildcarded view ids, and
* finally the global setting from Manager
*/
public Integer getTimeout(String viewId)
{
List<Page> stack = getPageStack(viewId);
for (int i=stack.size()-1; i>=0; i--)
{
Page page = stack.get(i);
Integer timeout = page.getTimeout();
if (timeout!=null)
{
return timeout;
}
}
return Manager.instance().getConversationTimeout();
}
public static String getSuffix()
{
String defaultSuffix = FacesContext.getCurrentInstance().getExternalContext()
.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME);
return defaultSuffix == null ? ViewHandler.DEFAULT_SUFFIX : defaultSuffix;
}
/**
* Parse a pages.xml file
*/
private void parse(InputStream stream)
{
Element root = getDocumentRoot(stream);
if (noConversationViewId==null) //let the setting in components.xml override the pages.xml
{
noConversationViewId = root.attributeValue("no-conversation-view-id");
}
if (loginViewId==null) //let the setting in components.xml override the pages.xml
{
loginViewId = root.attributeValue("login-view-id");
}
List<Element> elements = root.elements("conversation");
for (Element conversation : elements)
{
parseConversation(conversation, conversation.attributeValue("name"));
}
elements = root.elements("page");
for (Element page: elements)
{
parse( page, page.attributeValue("view-id") );
}
}
/**
* Parse a viewId.page.xml file
*/
private void parse(InputStream stream, String viewId)
{
parse( getDocumentRoot(stream), viewId );
}
/**
* Get the root element of the document
*/
private static Element getDocumentRoot(InputStream stream)
{
try
{
return XML.getRootElement(stream);
}
catch (DocumentException de)
{
throw new RuntimeException(de);
}
}
private void parseConversation(Element element, String name)
{
if (name == null)
{
throw new IllegalStateException("Must specify name for <conversation/> declaration");
}
if (conversations.containsKey(name))
{
throw new IllegalStateException("<conversation/> declaration already exists for [" + name + "]");
}
ELConversationIdParameter param = new ELConversationIdParameter(name,
element.attributeValue("parameter-name"),
element.attributeValue("parameter-value"));
conversations.put(name, param);
}
/**
* Parse a page element and add a Page to the map
*/
private void parse(Element element, String viewId)
{
if (viewId==null)
{
throw new IllegalStateException("Must specify view-id for <page/> declaration");
}
if ( viewId.endsWith("*") )
{
wildcardViewIds.add(viewId);
}
Page page = new Page(viewId);
pagesByViewId.put(viewId, page);
parsePage(page, element, viewId);
parseConversationControl( element, page.getConversationControl() );
parseTaskControl(element, page.getTaskControl());
parseProcessControl(element, page.getProcessControl());
List<Element> children = element.elements("param");
for (Element param: children)
{
page.getParameters().add( parseParam(param) );
}
List<Element> moreChildren = element.elements("navigation");
for (Element fromAction: moreChildren)
{
parseActionNavigation(page, fromAction);
}
Element restrict = element.element("restrict");
if (restrict != null)
{
page.setRestricted(true);
String expr = restrict.getTextTrim();
if ( !Strings.isEmpty(expr) ) page.setRestriction(expr);
}
}
/**
* Parse the attributes of page
*/
private Page parsePage(Page page, Element element, String viewId)
{
page.setSwitchEnabled( !"disabled".equals( element.attributeValue("switch") ) );
Element optionalElement = element.element("description");
String description = optionalElement==null ?
element.getTextTrim() : optionalElement.getTextTrim();
if (description!=null && description.length()>0)
{
page.setDescription(description);
}
String timeoutString = element.attributeValue("timeout");
if (timeoutString!=null)
{
page.setTimeout(Integer.parseInt(timeoutString));
}
page.setNoConversationViewId( element.attributeValue("no-conversation-view-id") );
page.setConversationRequired( "true".equals( element.attributeValue("conversation-required") ) );
page.setLoginRequired( "true".equals( element.attributeValue("login-required") ) );
page.setScheme( element.attributeValue("scheme") );
ConversationIdParameter param = conversations.get( element.attributeValue("conversation") );
if (param != null) page.setConversationIdParameter(param);
Element eventElement = element.element("raise-event");
if (eventElement!=null)
{
page.setEventType( eventElement.attributeValue("type") );
}
Action action = parseAction(element, "action");
if (action!=null) page.getActions().add(action);
List<Element> childElements = element.elements("action");
for (Element childElement: childElements)
{
page.getActions().add( parseAction(childElement, "execute") );
}
String bundle = element.attributeValue("bundle");
if (bundle!=null)
{
page.setResourceBundleName(bundle);
}
List<Element> moreChildElements = element.elements("in");
for (Element child: moreChildElements)
{
Input input = new Input();
input.setName( child.attributeValue("name") );
input.setValue( Expressions.instance().createValueExpression( child.attributeValue("value") ) );
String scopeName = child.attributeValue("scope");
if (scopeName!=null)
{
input.setScope( ScopeType.valueOf( scopeName.toUpperCase() ) );
}
page.getInputs().add(input);
}
return page;
}
private static Action parseAction(Element element, String actionAtt)
{
Action action = new Action();
String methodExpression = element.attributeValue(actionAtt);
if (methodExpression==null) return null;
if ( methodExpression.startsWith("#{") )
{
action.setMethodExpression( Expressions.instance().createMethodExpression(methodExpression) );
}
else
{
action.setOutcome(methodExpression);
}
String expression = element.attributeValue("if");
if (expression!=null)
{
action.setValueExpression( Expressions.instance().createValueExpression(expression) );
}
return action;
}
/**
* Parse end-conversation (and end-task) and begin-conversation (start-task and begin-task)
*
*/
private static void parseConversationControl(Element element, ConversationControl control)
{
Element endConversation = element.element("end-conversation");
endConversation = endConversation == null ? element.element("end-task") : endConversation;
if ( endConversation!=null )
{
control.setEndConversation(true);
control.setEndConversationBeforeRedirect( "true".equals( endConversation.attributeValue("before-redirect") ) );
String expression = endConversation.attributeValue("if");
if (expression!=null)
{
control.setEndConversationCondition( Expressions.instance().createValueExpression(expression, Boolean.class) );
}
}
Element beginConversation = element.element("begin-conversation");
beginConversation = beginConversation == null ? element.element("begin-task") : beginConversation;
beginConversation = beginConversation == null ? element.element("start-task") : beginConversation;
if ( beginConversation!=null )
{
control.setBeginConversation(true);
control.setJoin( "true".equals( beginConversation.attributeValue("join") ) );
control.setNested( "true".equals( beginConversation.attributeValue("nested") ) );
control.setPageflow( beginConversation.attributeValue("pageflow") );
String flushMode = beginConversation.attributeValue("flush-mode");
if (flushMode!=null)
{
control.setFlushMode( FlushModeType.valueOf( flushMode.toUpperCase() ) );
}
String expression = beginConversation.attributeValue("if");
if (expression!=null)
{
control.setBeginConversationCondition( Expressions.instance().createValueExpression(expression, Boolean.class) );
}
}
if ( control.isBeginConversation() && control.isEndConversation() )
{
throw new IllegalStateException("cannot use both <begin-conversation/> and <end-conversation/>");
}
}
/**
* Parse begin-task, start-task and end-task
*/
private static void parseTaskControl(Element element, TaskControl control)
{
Element endTask = element.element("end-task");
if ( endTask!=null )
{
control.setEndTask(true);
control.setTransition( endTask.attributeValue("transition") );
}
Element beginTask = element.element("begin-task");
if ( beginTask!=null )
{
control.setBeginTask(true);
String taskId = beginTask.attributeValue("task-id");
if (taskId==null)
{
taskId = "#{param.taskId}";
}
control.setTaskId( Expressions.instance().createValueExpression(taskId, String.class) );
}
Element startTask = element.element("start-task");
if ( startTask!=null )
{
control.setStartTask(true);
String taskId = startTask.attributeValue("task-id");
if (taskId==null)
{
taskId = "#{param.taskId}";
}
control.setTaskId( Expressions.instance().createValueExpression(taskId, String.class) );
}
if ( control.isBeginTask() && control.isEndTask() )
{
throw new IllegalStateException("cannot use both <begin-task/> and <end-task/>");
}
else if ( control.isBeginTask() && control.isStartTask() )
{
throw new IllegalStateException("cannot use both <start-task/> and <begin-task/>");
}
else if ( control.isStartTask() && control.isEndTask() )
{
throw new IllegalStateException("cannot use both <start-task/> and <end-task/>");
}
}
/**
* Parse create-process and end-process
*/
private static void parseProcessControl(Element element, ProcessControl control)
{
Element createProcess = element.element("create-process");
if ( createProcess!=null )
{
control.setCreateProcess(true);
control.setDefinition( createProcess.attributeValue("definition") );
}
Element resumeProcess = element.element("resume-process");
if ( resumeProcess!=null )
{
control.setResumeProcess(true);
String processId = resumeProcess.attributeValue("process-id");
if (processId==null)
{
processId = "#{param.processId}";
}
control.setProcessId( Expressions.instance().createValueExpression(processId, Long.class) );
}
if ( control.isCreateProcess() && control.isResumeProcess() )
{
throw new IllegalStateException("cannot use both <create-process/> and <resume-process/>");
}
}
private static void parseEvent(Element element, Rule rule)
{
Element eventElement = element.element("raise-event");
if ( eventElement!=null )
{
rule.setEventType( eventElement.attributeValue("type") );
}
}
/**
* Parse navigation
*/
private static void parseActionNavigation(Page entry, Element element)
{
Navigation navigation = new Navigation();
String outcomeExpression = element.attributeValue("evaluate");
if (outcomeExpression!=null)
{
navigation.setOutcome( Expressions.instance().createValueExpression(outcomeExpression) );
}
List<Element> cases = element.elements("rule");
for (Element childElement: cases)
{
navigation.getRules().add( parseRule(childElement) );
}
Rule rule = new Rule();
parseEvent(element, rule);
parseNavigationHandler(element, rule);
parseConversationControl( element, rule.getConversationControl() );
parseTaskControl(element, rule.getTaskControl());
parseProcessControl(element, rule.getProcessControl());
navigation.setRule(rule);
String expression = element.attributeValue("from-action");
if (expression==null)
{
if (entry.getDefaultNavigation()==null)
{
entry.setDefaultNavigation(navigation);
}
else
{
throw new IllegalStateException("multiple catchall <navigation> elements");
}
}
else
{
Object old = entry.getNavigations().put(expression, navigation);
if (old!=null)
{
throw new IllegalStateException("multiple <navigation> elements for action: " + expression);
}
}
}
/**
* Parse param
*/
private static Param parseParam(Element element)
{
String valueExpression = element.attributeValue("value");
String name = element.attributeValue("name");
if (name==null)
{
if (valueExpression==null)
{
throw new IllegalArgumentException("must specify name or value for page <param/> declaration");
}
name = valueExpression.substring(2, valueExpression.length()-1);
}
Param param = new Param(name);
if (valueExpression!=null)
{
param.setValueExpression(Expressions.instance().createValueExpression(valueExpression));
}
param.setConverterId(element.attributeValue("converterId"));
String converterExpression = element.attributeValue("converter");
if (converterExpression!=null)
{
param.setConverterValueExpression(Expressions.instance().createValueExpression(converterExpression));
}
param.setValidatorId(element.attributeValue("validatorId"));
String validatorExpression = element.attributeValue("validator");
if (converterExpression!=null)
{
param.setValidatorValueExpression(Expressions.instance().createValueExpression(validatorExpression));
}
param.setRequired( "true".equals( element.attributeValue("required") ) );
return param;
}
/**
* Parse rule
*/
private static Rule parseRule(Element element)
{
Rule rule = new Rule();
rule.setOutcomeValue( element.attributeValue("if-outcome") );
String expression = element.attributeValue("if");
if (expression!=null)
{
rule.setCondition( Expressions.instance().createValueExpression(expression) );
}
parseConversationControl( element, rule.getConversationControl() );
parseTaskControl(element, rule.getTaskControl());
parseProcessControl(element, rule.getProcessControl());
parseEvent(element, rule);
parseNavigationHandler(element, rule);
return rule;
}
private static void parseNavigationHandler(Element element, Rule rule)
{
Element render = element.element("render");
if (render!=null)
{
final String viewId = render.attributeValue("view-id");
Element messageElement = render.element("message");
String message = messageElement==null ? null : messageElement.getTextTrim();
String control = messageElement==null ? null : messageElement.attributeValue("for");
String severityName = messageElement==null ? null : messageElement.attributeValue("severity");
Severity severity = severityName==null ?
FacesMessage.SEVERITY_INFO :
getFacesMessageValuesMap().get( severityName.toUpperCase() );
rule.addNavigationHandler( new RenderNavigationHandler(viewId, message, severity, control) );
}
Element redirect = element.element("redirect");
if (redirect!=null)
{
List<Element> children = redirect.elements("param");
final List<Param> params = new ArrayList<Param>();
for (Element child: children)
{
params.add( parseParam(child) );
}
final String viewId = redirect.attributeValue("view-id");
Element messageElement = redirect.element("message");
String control = messageElement==null ? null : messageElement.attributeValue("for");
String message = messageElement==null ? null : messageElement.getTextTrim();
String severityName = messageElement==null ? null : messageElement.attributeValue("severity");
Severity severity = severityName==null ?
FacesMessage.SEVERITY_INFO :
getFacesMessageValuesMap().get( severityName.toUpperCase() );
rule.addNavigationHandler( new RedirectNavigationHandler(viewId, params, message, severity, control) );
}
List<Element> childElements = element.elements("out");
for (Element child: childElements)
{
Output output = new Output();
output.setName( child.attributeValue("name") );
output.setValue( Expressions.instance().createValueExpression( child.attributeValue("value") ) );
String scopeName = child.attributeValue("scope");
if (scopeName==null)
{
output.setScope(ScopeType.CONVERSATION);
}
else
{
output.setScope( ScopeType.valueOf( scopeName.toUpperCase() ) );
}
rule.getOutputs().add(output);
}
}
public static Map<String, Severity> getFacesMessageValuesMap()
{
Map<String, Severity> result = new HashMap<String, Severity>();
for (Map.Entry<String, Severity> me: (Set<Map.Entry<String, Severity>>) FacesMessage.VALUES_MAP.entrySet())
{
result.put( me.getKey().toUpperCase(), me.getValue() );
}
return result;
}
public String getLoginViewId()
{
return loginViewId;
}
public void setLoginViewId(String loginViewId)
{
this.loginViewId = loginViewId;
}
public static String getCurrentViewId()
{
return getViewId( FacesContext.getCurrentInstance() );
}
public static String getViewId(FacesContext facesContext)
{
if (facesContext!=null)
{
UIViewRoot viewRoot = facesContext.getViewRoot();
if (viewRoot!=null) return viewRoot.getViewId();
}
return null;
}
public Integer getHttpPort()
{
return httpPort;
}
public void setHttpPort(Integer httpPort)
{
this.httpPort = httpPort;
}
public Integer getHttpsPort()
{
return httpsPort;
}
public void setHttpsPort(Integer httpsPort)
{
this.httpsPort = httpsPort;
}
public String[] getResources()
{
return resources;
}
public void setResources(String[] resources)
{
this.resources = resources;
}
public static boolean isDebugPage()
{
return Init.instance().isDebug() &&
( FacesContext.getCurrentInstance() != null ) &&
"/debug.xhtml".equals( getCurrentViewId() );
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Param.java
Index: Param.java
===================================================================
package org.jboss.seam.navigation;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import org.jboss.seam.core.Expressions.ValueExpression;
import org.jboss.seam.faces.JsfExpressions;
public final class Param
{
private final String name;
private ValueExpression valueExpression;
private boolean required;
private ValueExpression converterValueExpression;
private String converterId;
private ValueExpression validatorValueExpression;
private String validatorId;
public Param(String name)
{
this.name = name;
}
public Converter getConverter()
{
if (converterId!=null)
{
return FacesContext.getCurrentInstance().getApplication().createConverter(converterId);
}
else if (converterValueExpression!=null)
{
return (Converter) converterValueExpression.getValue();
}
else if (valueExpression==null)
{
return null;
}
else
{
Class<?> type = valueExpression.getType();
return FacesContext.getCurrentInstance().getApplication().createConverter(type);
}
}
public Validator getValidator()
{
if (validatorId!=null)
{
return FacesContext.getCurrentInstance().getApplication().createValidator(converterId);
}
else if (validatorValueExpression!=null)
{
return (Validator) validatorValueExpression.getValue();
}
else
{
return null;
}
}
public String getName()
{
return name;
}
public void setValueExpression(ValueExpression valueExpression)
{
this.valueExpression = valueExpression;
}
public ValueExpression getValueExpression()
{
return valueExpression;
}
public void setConverterValueExpression(ValueExpression converterValueExpression)
{
this.converterValueExpression = converterValueExpression;
}
public ValueExpression getConverterValueExpression()
{
return converterValueExpression;
}
public void setConverterId(String converterId)
{
this.converterId = converterId;
}
public String getConverterId()
{
return converterId;
}
@Override
public String toString()
{
return "PageParameter(" + name + ")";
}
/**
* Get the current value of a page or redirection parameter
* from the model, and convert to a String
*/
public Object getValueFromModel(FacesContext facesContext)
{
Object value = getValueExpression().getValue();
if (value==null)
{
return null;
}
else
{
Converter converter = null;
try
{
converter = getConverter();
}
catch (RuntimeException re)
{
//YUCK! due to bad JSF/MyFaces error handling
return null;
}
return converter==null ?
value :
converter.getAsString( facesContext, facesContext.getViewRoot(), value );
}
}
/**
* Get the current value of a page parameter from the request parameters
*/
public Object getValueFromRequest(FacesContext facesContext, Map<String, String[]> requestParameters)
throws ValidatorException
{
String[] parameterValues = requestParameters.get( getName() );
if (parameterValues==null || parameterValues.length==0)
{
if ( isRequired() )
{
addRequiredMessage(facesContext);
}
return null;
}
if (parameterValues.length>1)
{
throw new IllegalArgumentException("page parameter may not be multi-valued: " + getName());
}
String stringValue = parameterValues[0];
//Note: for not-required fields, we behave a
//but different than JSF for empty strings.
//is this a bad thing? (but we are the same
//for required fields)
if ( stringValue.length()==0 && isRequired() )
{
addRequiredMessage(facesContext);
return null;
}
Converter converter = null;
try
{
converter = getConverter();
}
catch (RuntimeException re)
{
//YUCK! due to bad JSF/MyFaces error handling
return null;
}
Object value = converter==null ?
stringValue :
converter.getAsObject( facesContext, facesContext.getViewRoot(), stringValue );
Validator validator = getValidator();
if (validator!=null)
{
validator.validate( facesContext, facesContext.getViewRoot(), value );
}
if (valueExpression!=null)
{
JsfExpressions.instance().validate( valueExpression.getExpressionString(), value );
}
return value;
}
private void addRequiredMessage(FacesContext facesContext)
{
String bundleName = facesContext.getApplication().getMessageBundle();
if (bundleName==null) bundleName = FacesMessage.FACES_MESSAGES;
ResourceBundle resourceBundle = facesContext.getApplication().getResourceBundle(facesContext, bundleName);
//TODO: this should not be necessary!
if (resourceBundle==null)
{
resourceBundle = org.jboss.seam.international.ResourceBundle.instance();
}
throw new ValidatorException( new FacesMessage(
FacesMessage.SEVERITY_ERROR,
resourceBundle.getString("javax.faces.component.UIInput.REQUIRED"),
resourceBundle.getString("javax.faces.component.UIInput.REQUIRED_detail")
) );
}
public String getValidatorId()
{
return validatorId;
}
public void setValidatorId(String validatorId)
{
this.validatorId = validatorId;
}
public ValueExpression getValidatorValueExpression()
{
return validatorValueExpression;
}
public void setValidatorValueExpression(ValueExpression validatorValueExpression)
{
this.validatorValueExpression = validatorValueExpression;
}
public boolean isRequired()
{
return required;
}
public void setRequired(boolean required)
{
this.required = required;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/ProcessControl.java
Index: ProcessControl.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.bpm.BusinessProcess;
import org.jboss.seam.core.Expressions.ValueExpression;
public class ProcessControl
{
private boolean isCreateProcess;
private boolean isResumeProcess;
private String definition;
private ValueExpression<Long> processId;
public void createOrResumeProcess()
{
if ( createProcess() )
{
BusinessProcess.instance().createProcess(definition);
}
if ( resumeProcess() )
{
BusinessProcess.instance().resumeProcess( processId.getValue() );
}
}
private boolean createProcess()
{
return isCreateProcess;
}
private boolean resumeProcess()
{
return isResumeProcess;
}
public boolean isCreateProcess()
{
return isCreateProcess;
}
public void setCreateProcess(boolean isCreateProcess)
{
this.isCreateProcess = isCreateProcess;
}
public boolean isResumeProcess()
{
return isResumeProcess;
}
public void setResumeProcess(boolean isResumeProcess)
{
this.isResumeProcess = isResumeProcess;
}
public String getDefinition()
{
return definition;
}
public void setDefinition(String definition)
{
this.definition = definition;
}
public ValueExpression<Long> getProcessId()
{
return processId;
}
public void setProcessId(ValueExpression<Long> processId)
{
this.processId = processId;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Put.java
Index: Put.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.ScopeType;
import org.jboss.seam.core.Expressions.ValueExpression;
public class Put
{
private String name;
private ScopeType scope;
private ValueExpression value;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public ScopeType getScope()
{
return scope;
}
public void setScope(ScopeType scope)
{
this.scope = scope;
}
public ValueExpression getValue()
{
return value;
}
public void setValue(ValueExpression value)
{
this.value = value;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/RedirectNavigationHandler.java
Index: RedirectNavigationHandler.java
===================================================================
package org.jboss.seam.navigation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;
public final class RedirectNavigationHandler extends NavigationHandler
{
private final String viewId;
private final List<Param> params;
private final String message;
private final Severity severity;
private final String control;
public RedirectNavigationHandler(String viewId, List<Param> params, String message, Severity severity, String control)
{
this.viewId = viewId;
this.params = params;
this.message = message;
this.severity = severity;
this.control = control;
}
@Override
public boolean navigate(FacesContext context)
{
addFacesMessage(message, severity, control);
Map<String, Object> parameters = new HashMap<String, Object>();
for ( Param parameter: params )
{
Object value = parameter.getValueFromModel(context);
//render it even if the value is null, since we want it
//to override page parameter values which would be
//appended by the redirect filter
//if (value!=null)
//{
parameters.put( parameter.getName(), value );
//}
}
redirect(viewId, parameters);
return true;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/RenderNavigationHandler.java
Index: RenderNavigationHandler.java
===================================================================
package org.jboss.seam.navigation;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;
public final class RenderNavigationHandler extends NavigationHandler
{
private final String viewId;
private final String message;
private final Severity severity;
private final String control;
public RenderNavigationHandler(String viewId, String message, Severity severity, String control)
{
this.viewId = viewId;
this.message = message;
this.severity = severity;
this.control = control;
}
@Override
public boolean navigate(FacesContext context)
{
addFacesMessage(message, severity, control);
render(viewId);
return true;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/Rule.java
Index: Rule.java
===================================================================
package org.jboss.seam.navigation;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Expressions.ValueExpression;
public final class Rule
{
private String outcomeValue;
private ValueExpression condition;
private List<Output> outputs = new ArrayList<Output>();
private ConversationControl conversationControl = new ConversationControl();
private TaskControl taskControl = new TaskControl();
private ProcessControl processControl = new ProcessControl();
private List<NavigationHandler> navigationHandlers = new ArrayList<NavigationHandler>();
private String eventType;
public boolean matches(String actualValue)
{
return ( actualValue!=null || condition!=null ) &&
( outcomeValue==null || outcomeValue.equals(actualValue) ) &&
( condition==null || Boolean.TRUE.equals( condition.getValue() ) );
}
public List<NavigationHandler> getNavigationHandlers()
{
return navigationHandlers;
}
public void addNavigationHandler(NavigationHandler navigationHandler)
{
this.navigationHandlers.add(navigationHandler);
}
public ConversationControl getConversationControl()
{
return conversationControl;
}
public TaskControl getTaskControl()
{
return taskControl;
}
public ProcessControl getProcessControl()
{
return processControl;
}
public ValueExpression getCondition()
{
return condition;
}
public void setCondition(ValueExpression expression)
{
this.condition = expression;
}
public String getOutcomeValue()
{
return outcomeValue;
}
public void setOutcomeValue(String value)
{
this.outcomeValue = value;
}
public List<Output> getOutputs()
{
return outputs;
}
public boolean execute(FacesContext context)
{
getConversationControl().beginOrEndConversation();
getTaskControl().beginOrEndTask();
getProcessControl().createOrResumeProcess();
for ( Output output: getOutputs() )
{
output.out();
}
if (eventType!=null)
{
Events.instance().raiseEvent(eventType);
}
for ( NavigationHandler nh: getNavigationHandlers() )
{
if ( nh.navigate(context) ) return true;
}
return false;
}
public String getEventType()
{
return eventType;
}
public void setEventType(String event)
{
this.eventType = event;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/SafeActions.java
Index: SafeActions.java
===================================================================
package org.jboss.seam.navigation;
import static org.jboss.seam.InterceptionType.NEVER;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
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.Intercept;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.contexts.Contexts;
@Scope(ScopeType.APPLICATION)
@Intercept(NEVER)
@Name("org.jboss.seam.core.safeActions")
@Install(precedence=BUILT_IN)
public class SafeActions
{
private Set<String> safeActions = Collections.synchronizedSet( new HashSet<String>() );
public static String toActionId(String viewId, String expression)
{
return viewId.substring(1) + ':' + expression.substring( 2, expression.length()-1 );
}
public static String toAction(String id)
{
int loc = id.indexOf(':');
if (loc<0) throw new IllegalArgumentException();
return "#{" + id.substring(loc+1) + "}";
}
public void addSafeAction(String id)
{
safeActions.add(id);
}
public boolean isActionSafe(String id)
{
if ( safeActions.contains(id) ) return true;
int loc = id.indexOf(':');
if (loc<0) throw new IllegalArgumentException();
String viewId = id.substring(0, loc);
String action = "\"#{" + id.substring(loc+1) + "}\"";
InputStream is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(viewId);
if (is==null) throw new IllegalStateException();
BufferedReader reader = new BufferedReader( new InputStreamReader(is) );
try
{
while ( reader.ready() )
{
if ( reader.readLine().contains(action) )
{
addSafeAction(id);
return true;
}
}
return false;
}
catch (IOException ioe)
{
throw new RuntimeException(ioe);
}
finally
{
try
{
reader.close();
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
public static SafeActions instance()
{
if ( !Contexts.isApplicationContextActive() )
{
throw new IllegalStateException("No active application context");
}
return (SafeActions) Component.getInstance(SafeActions.class, ScopeType.APPLICATION);
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/SyntheticConversationIdParameter.java
Index: SyntheticConversationIdParameter.java
===================================================================
package org.jboss.seam.navigation;
import java.util.Map;
import org.jboss.seam.core.ConversationPropagation;
import org.jboss.seam.core.Manager;
import org.jboss.seam.util.Id;
public class SyntheticConversationIdParameter implements ConversationIdParameter
{
public String getName()
{
return null;
}
public String getParameterName()
{
return Manager.instance().getConversationIdParameter();
}
public String getParameterValue()
{
return Manager.instance().getCurrentConversationId();
}
public String getInitialConversationId(Map parameters)
{
return Id.nextId();
}
public String getConversationId()
{
return Id.nextId();
}
public String getRequestConversationId(Map parameters)
{
return ConversationPropagation.getRequestParameterValue( parameters, getParameterName() );
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/TaskControl.java
Index: TaskControl.java
===================================================================
package org.jboss.seam.navigation;
import org.jboss.seam.bpm.BusinessProcess;
import org.jboss.seam.core.Expressions.ValueExpression;
public class TaskControl
{
private boolean isBeginTask;
private boolean isStartTask;
private boolean isEndTask;
private ValueExpression taskId;
private String transition;
public void beginOrEndTask()
{
if ( endTask() )
{
BusinessProcess.instance().validateTask();
BusinessProcess.instance().endTask(transition);
}
if ( beginTask() || startTask() )
{
Object id = taskId.getValue();
if (id==null)
{
throw new IllegalStateException("task id may not be null");
}
Long taskId;
if ( id instanceof Long )
{
taskId = (Long) id;
}
else if (id instanceof String)
{
taskId = new Long( (String) id );
}
else
{
throw new IllegalArgumentException("task id must be a string or long");
}
BusinessProcess.instance().resumeTask(taskId);
}
if ( startTask() )
{
BusinessProcess.instance().startTask();
}
}
private boolean beginTask()
{
return isBeginTask && taskId.getValue() != null;
}
private boolean startTask()
{
return isStartTask && taskId.getValue() != null;
}
private boolean endTask()
{
return isEndTask;
}
public boolean isBeginTask()
{
return isBeginTask;
}
public void setBeginTask(boolean isBeginTask)
{
this.isBeginTask = isBeginTask;
}
public boolean isEndTask()
{
return isEndTask;
}
public void setEndTask(boolean isEndTask)
{
this.isEndTask = isEndTask;
}
public boolean isStartTask()
{
return isStartTask;
}
public void setStartTask(boolean isStartTask)
{
this.isStartTask = isStartTask;
}
public void setTaskId(ValueExpression<String> taskId)
{
this.taskId = taskId;
}
public ValueExpression<String> getTaskId()
{
return taskId;
}
public String getTransition()
{
return transition;
}
public void setTransition(String transition)
{
this.transition = transition;
}
}
1.1 date: 2007/06/19 19:13:55; author: gavin; state: Exp;jboss-seam/src/main/org/jboss/seam/navigation/package-info.java
Index: package-info.java
===================================================================
@Namespace(value="http://jboss.com/products/seam/navigation", prefix="org.jboss.seam.navigation")
package org.jboss.seam.navigation;
import org.jboss.seam.annotations.Namespace;
More information about the jboss-cvs-commits
mailing list