Package org.jboss.seam.core

Source Code of org.jboss.seam.core.Pages

package org.jboss.seam.core;
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.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.Expressions.MethodBinding;
import org.jboss.seam.core.Expressions.ValueBinding;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jboss.seam.pages.Action;
import org.jboss.seam.pages.ConversationControl;
import org.jboss.seam.pages.ConversationIdParameter;
import org.jboss.seam.pages.ELConversationIdParameter;
import org.jboss.seam.pages.Input;
import org.jboss.seam.pages.Navigation;
import org.jboss.seam.pages.Output;
import org.jboss.seam.pages.Page;
import org.jboss.seam.pages.Param;
import org.jboss.seam.pages.ProcessControl;
import org.jboss.seam.pages.RedirectNavigationHandler;
import org.jboss.seam.pages.RenderNavigationHandler;
import org.jboss.seam.pages.Rule;
import org.jboss.seam.pages.TaskControl;
import org.jboss.seam.security.Identity;
import org.jboss.seam.security.NotLoggedInException;
import org.jboss.seam.util.Parameters;
import org.jboss.seam.util.Resources;
import org.jboss.seam.util.Strings;
import org.jboss.seam.util.XML;
/**
* 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 = null;
   private Integer httpsPort = null;
   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()
   {
      InputStream stream = Resources.getResourceAsStream("/WEB-INF/pages.xml");     
      if (stream==null)
      {
         log.debug("no pages.xml file found");
      }
      else
      {
         log.debug("reading pages.xml");
         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, 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
    */
   public boolean enterPage(FacesContext facesContext)
   {
      boolean result = false;
      String viewId = getViewId(facesContext);
     
      String requestScheme = getRequestScheme(facesContext);
      if ( requestScheme!=null )
      {
         String scheme = getScheme(viewId);
         if ( scheme!=null && !requestScheme.equals(scheme) )
         {
            Manager.instance().redirect(viewId);             
            return result;
         }
      }
     
      for ( Page page: getPageStack(viewId) )
      {        
         if ( isNoConversationRedirectRequired(page) )
         {
            redirectToNoConversationView();
            return result;
         }
         else if ( isLoginRedirectRequired(viewId, page) )
         {
            redirectToLoginView();
            return result;
         }
         else
         {
            result = page.enter(facesContext) || result;
         }
      }
     
      //run the s:link / s:button action after checking the
      //conversation existence!
      result = callAction(facesContext) || result;
      return result;
   }
  
   private boolean isNoConversationRedirectRequired(Page page)
   {
      return page.isConversationRequired() &&
            !Manager.instance().isLongRunningConversation();
   }
  
   private boolean isLoginRedirectRequired(String viewId, Page page)
   {
      return page.isLoginRequired() &&
            !viewId.equals( getLoginViewId() ) &&
            !Identity.instance().isLoggedIn();
   }
  
   private 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.core.FacesPage facesPage = org.jboss.seam.core.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 = (String) facesContext.getExternalContext()
            .getRequestParameterMap()
            .get("actionOutcome");
      String fromAction = outcome;
     
      if (outcome==null)
      {
         String actionId = (String) facesContext.getExternalContext()
               .getRequestParameterMap()
               .get("actionMethod");
         if (actionId!=null)
         {
            if ( !SafeActions.instance().isActionSafe(actionId) ) return result;
            String expression = SafeActions.toAction(actionId);
            result = true;
            MethodBinding actionBinding = Expressions.instance().createMethodBinding(expression);
            outcome = toString( actionBinding.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() )
         {
            ValueBinding valueBinding = pageParameter.getValueBinding();
            Object value;
            if (valueBinding==null)
            {
               value = Contexts.getPageContext().get( pageParameter.getName() );
            }
            else
            {
               value = valueBinding.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)
   {
      ValueBinding valueBinding = pageParameter.getValueBinding();
      if (valueBinding==null)
      {
         return Contexts.getPageContext().get( pageParameter.getName() );
      }
      else
      {
         return pageParameter.getValueFromModel(facesContext);
      }
   }
  
   /**
    * Apply any page parameters passed as parameter values to the model.
    */
   public void applyRequestParameterValues(FacesContext facesContext)
   {
      //first store the page parameters into the viewroot, so that if
      //we fail while applying to the model, we can still make
      //Redirect.captureCurrentView() work.
      String viewId = getViewId(facesContext);
      Map<String, String[]> requestParameters = Parameters.getRequestParameters();
      for ( Page page: getPageStack(viewId) )
      {
         for ( Param pageParameter: page.getParameters() )
         { 
            Object value = pageParameter.getValueFromRequest(facesContext, requestParameters);
            if (value==null)
            {
               Contexts.getPageContext().remove( pageParameter.getName() );
            }
            else
            {
               Contexts.getPageContext().set( pageParameter.getName(), value );
            }
         }
      }
     
      //now apply them to the model
      applyViewRootValues(facesContext);
   }
  
   /**
    * Apply any page parameters passed as view root attributes to the model.
    */
   public void applyViewRootValues(FacesContext facesContext)
   {
      String viewId = getViewId(facesContext);
      for ( Page page: getPageStack(viewId) )
      {
         for ( Param pageParameter: page.getParameters() )
         {        
            ValueBinding valueBinding = pageParameter.getValueBinding();
            if (valueBinding!=null)
            {
               Object object = Contexts.getPageContext().get( pageParameter.getName() );
               if (object!=null)
               {
                  valueBinding.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.putpageParameter.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);
     
      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().createValueBinding( 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("#{") )
      {
         MethodBinding methodBinding = Expressions.instance().createMethodBinding(methodExpression);
         action.setMethodBinding(methodBinding);
      }
      else
      {
         action.setOutcome(methodExpression);
      }
      String expression = element.attributeValue("if");
      if (expression!=null)
      {
         action.setValueBinding( Expressions.instance().createValueBinding(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().createValueBinding(expression) );
         }
      }
     
      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().createValueBinding(expression) );
         }
      }
     
      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().createValueBinding(taskId) );
      }
     
      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().createValueBinding(taskId) );
      }
     
      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().createValueBinding(processId) );
      }
     
      if ( control.isCreateProcess() && control.isResumeProcess() )
      {
         throw new IllegalStateException("cannot use both <create-process/> and <resume-process/>");
      }
   }
  
   /**
    * 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().createValueBinding(outcomeExpression) );
      }
     
      List<Element> cases = element.elements("rule");
      for (Element childElement: cases)
      {
         navigation.getRules().add( parseRule(childElement) );
      }
     
      Rule rule = new 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.setValueBinding(Expressions.instance().createValueBinding(valueExpression));
      }
      param.setConverterId(element.attributeValue("converterId"));
      String converterExpression = element.attributeValue("converter");
      if (converterExpression!=null)
      {
         param.setConverterValueBinding(Expressions.instance().createValueBinding(converterExpression));
      }
      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().createValueBinding(expression)  );
      }
     
      parseConversationControl( element, rule.getConversationControl() );
      parseTaskControl(element, rule.getTaskControl());
      parseProcessControl(element, rule.getProcessControl());
      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 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) );
      }
     
      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 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) );
      }
     
      List<Element> childElements = element.elements("out");
      for (Element child: childElements)
      {
         Output output = new Output();
         output.setName( child.attributeValue("name") );
         output.setValue( Expressions.instance().createValueBinding( 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;
   }
  
}
TOP

Related Classes of org.jboss.seam.core.Pages

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.