[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 &lt;conversation/&gt; 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