[seam-commits] Seam SVN: r10601 - in modules/trunk: faces and 8 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Apr 22 21:09:20 EDT 2009


Author: shane.bryzak at jboss.com
Date: 2009-04-22 21:09:20 -0400 (Wed, 22 Apr 2009)
New Revision: 10601

Added:
   modules/trunk/faces/
   modules/trunk/faces/pom.xml
   modules/trunk/faces/src/
   modules/trunk/faces/src/main/
   modules/trunk/faces/src/main/java/
   modules/trunk/faces/src/main/java/org/
   modules/trunk/faces/src/main/java/org/jboss/
   modules/trunk/faces/src/main/java/org/jboss/seam/
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/DataModels.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/DateConverter.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesContext.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesExpressions.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesManager.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesMessages.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesPage.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/HttpError.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/IsUserInRole.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Navigator.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Parameters.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Redirect.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/RedirectException.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Renderer.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/ResourceLoader.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Selector.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Switcher.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/UiComponent.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/UserPrincipal.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/Validation.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/events/
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/events/ValidationFailedEvent.java
   modules/trunk/faces/src/main/java/org/jboss/seam/faces/package-info.java
Log:
initial import of faces module

Added: modules/trunk/faces/pom.xml
===================================================================
--- modules/trunk/faces/pom.xml	                        (rev 0)
+++ modules/trunk/faces/pom.xml	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,36 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">   
+   <parent>
+      <artifactId>seam-parent</artifactId>
+      <groupId>org.jboss.seam</groupId>      
+      <version>3.0.0-SNAPSHOT</version>
+   </parent>    
+  
+   <modelVersion>4.0.0</modelVersion>   
+   <groupId>org.jboss.seam</groupId>
+   <artifactId>seam-faces</artifactId>
+   <packaging>jar</packaging>
+   <version>3.0.0-SNAPSHOT</version>
+   <name>Seam Faces</name>
+         
+   <dependencies>
+      <dependency>
+         <groupId>javax.servlet</groupId>
+         <artifactId>servlet-api</artifactId>
+      </dependency>
+      <dependency>
+         <groupId>javax.el</groupId>
+         <artifactId>el-api</artifactId>
+      </dependency>   
+      <dependency>
+         <groupId>org.jboss.webbeans</groupId>
+         <artifactId>jsr299-api</artifactId>
+      </dependency>   
+      <dependency>
+         <groupId>javax.faces</groupId>
+         <artifactId>jsf-api</artifactId>
+      </dependency>  
+   </dependencies>
+
+</project>

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/DataModels.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/DataModels.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/DataModels.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,70 @@
+package org.jboss.seam.faces;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.model.DataModel;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.framework.Query;
+import org.jboss.seam.jsf.ArrayDataModel;
+import org.jboss.seam.jsf.ListDataModel;
+import org.jboss.seam.jsf.MapDataModel;
+import org.jboss.seam.jsf.SetDataModel;
+
+/**
+ * Wraps a collection as a JSF {@link DataModel}. May be overridden
+ * and extended if you don't like the built in collections
+ * which are supported: list, map, set, array.
+ *
+ * @author pmuir
+ */
+public class DataModels
+{
+   
+   /**
+    * Wrap the value in a DataModel
+    * 
+    * This implementation supports {@link List}, {@link Map}, {@link Set} and
+    * arrays
+    */
+   public DataModel getDataModel(Object value)
+   {
+      if (value instanceof List)
+      {
+         return new ListDataModel( (List) value );
+      }
+      else if (value instanceof Object[])
+      {
+         return new ArrayDataModel( (Object[]) value ); 
+      }
+      else if (value instanceof Map)
+      {
+         return new MapDataModel( (Map) value );
+      }
+      else if (value instanceof Set)
+      {
+         return new SetDataModel( (Set) value );
+      }
+      else
+      {
+         throw new IllegalArgumentException("unknown collection type: " + value.getClass());
+      }
+   }
+   
+   /**
+    * Wrap the the Seam Framework {@link Query} in a JSF DataModel
+    */
+   public DataModel getDataModel(Query query)
+   {
+      return getDataModel( query.getResultList() );
+   }
+   
+   public static DataModels instance()
+   {
+      return (DataModels) Component.getInstance(DataModels.class, ScopeType.STATELESS);
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/DateConverter.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/DateConverter.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/DateConverter.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,120 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.ConverterException;
+
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.faces.Converter;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.log.Log;
+import org.jboss.seam.log.Logging;
+
+/**
+ * Provides a default JSF converter for properties of type java.util.Date.
+ * 
+ * <p>This converter is provided to save a developer from having to specify
+ * a DateTimeConverter on an input field or page parameter. By default, it
+ * assumes the type to be a date (as opposed to a time or date plus time) and
+ * uses the short input style adjusted to the Locale of the user. For Locale.US,
+ * the input pattern is mm/DD/yy. However, to comply with Y2K, the year is changed
+ * from two digits to four (e.g., mm/DD/yyyy).</p>
+ * <p>It's possible to override the input pattern globally using component configuration.
+ * Here is an example of changing the style to both and setting the date and
+ * time style to medium.</p>
+ * <pre>
+ * org.jboss.seam.faces.dateConverter.type=both
+ * org.jboss.seam.faces.dateConverter.dateStyle=medium
+ * org.jboss.seam.faces.dateConverter.timeStyle=medium
+ * </pre>
+ * <p>Alternatively, a fixed pattern can be specified.</p>
+ * <pre>
+ * org.jboss.seam.faces.dateConverter.pattern=yyyy-mm-DD
+ * </pre>
+ * 
+ * @author Dan Allen
+ */
+ at Converter(forClass = Date.class)
+ at Name("org.jboss.seam.faces.dateConverter")
+ at Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
+ at BypassInterceptors
+public class DateConverter extends javax.faces.convert.DateTimeConverter {
+
+	private Log log = Logging.getLog(DateConverter.class);
+
+	private static final String TYPE_DATE = "date";
+	private static final String STYLE_SHORT = "short";
+	private static final String TWO_DIGIT_YEAR_PATTERN = "yy";
+	private static final String FOUR_DIGIT_YEAR_PATTERN = "yyyy";
+	
+	// constructor is used to initialize converter to allow these values to be overridden using component properties
+	public DateConverter() {
+		super();
+		setType(TYPE_DATE);
+		setDateStyle(STYLE_SHORT);
+		setTimeStyle(STYLE_SHORT); // default in case developer overrides type to be time or both
+	}
+	
+	@Create
+	public void create() {
+		// TODO make this work if using "both" for type; requires more analysis of time style
+		if (TYPE_DATE.equals(getType()) && STYLE_SHORT.equals(getDateStyle()) && getPattern() == null) {
+			// attempt to make the pattern Y2K compliant, which it isn't by default
+			DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, getLocale());
+			if (dateFormat instanceof SimpleDateFormat) {
+				setPattern(((SimpleDateFormat) dateFormat).toPattern().replace(TWO_DIGIT_YEAR_PATTERN, FOUR_DIGIT_YEAR_PATTERN));
+			}
+		}
+		// required since the superclass may access the fields directly
+		setTimeZone(getTimeZone());
+		setLocale(getLocale());
+	}
+
+	@Override
+	public TimeZone getTimeZone() {
+		if (Contexts.isApplicationContextActive()) {
+			return org.jboss.seam.international.TimeZone.instance();
+		} else {
+			// we don't want to use JSF's braindead default (maybe in JSF 2)
+			return TimeZone.getDefault();
+		}
+	}
+
+	@Override
+	public Locale getLocale() {
+		if (Contexts.isApplicationContextActive()) {
+			return org.jboss.seam.international.Locale.instance();
+		} else {
+			return super.getLocale();
+		}
+	}
+
+	@Override
+	public Object getAsObject(FacesContext context, UIComponent component,
+			String value) throws ConverterException {
+		if (log.isDebugEnabled()) {
+			log.debug("Converting string '#0' to date for clientId '#1' using Seam's built-in JSF date converter", value, component.getClientId(context));
+		}
+		return super.getAsObject(context, component, value);
+	}
+
+	@Override
+	public String getAsString(FacesContext context, UIComponent component,
+			Object value) throws ConverterException {
+		if (log.isDebugEnabled()) {
+			log.debug("Converting date '#0' to string for clientId '#1' using Seam's built-in JSF date converter", value, component.getClientId(context));
+		}
+		return super.getAsString(context, component, value);
+	}
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesContext.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesContext.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesContext.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,29 @@
+//$Id: FacesContext.java 5350 2007-06-20 17:53:19Z gavin $
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * Support for injecting the JSF FacesContext object
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.APPLICATION)
+ at BypassInterceptors
+ at Name("org.jboss.seam.faces.facesContext")
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+public class FacesContext
+{
+   @Unwrap
+   public javax.faces.context.FacesContext getContext()
+   {
+      return javax.faces.context.FacesContext.getCurrentInstance();
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesExpressions.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesExpressions.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesExpressions.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,37 @@
+//$Id: FacesExpressions.java 9684 2008-12-01 21:41:20Z dan.j.allen $
+package org.jboss.seam.faces;
+
+import javax.annotation.Named;
+import javax.context.ApplicationScoped;
+import javax.el.ELContext;
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.contexts.FacesLifecycle;
+import org.jboss.seam.core.Expressions;
+
+/**
+ * Factory for method and value bindings in a JSF environment.
+ * 
+ * @author Gavin King
+ */
+ at Named
+ at ApplicationScoped
+public class FacesExpressions extends Expressions
+{   
+   /**
+    * Get an appropriate ELContext. If there is an active JSF request,
+    * use JSF's ELContext. Otherwise, use one that we created.
+    */
+   @Override
+   public ELContext getELContext()
+   {
+      return isFacesContextActive() ? FacesContext.getCurrentInstance().getELContext() : super.getELContext();
+   }
+   
+   @Override
+   protected boolean isFacesContextActive()
+   { 
+      return FacesContext.getCurrentInstance() != null && FacesLifecycle.getPhaseId() != null;
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesManager.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesManager.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesManager.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,316 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseId;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.FacesLifecycle;
+import org.jboss.seam.core.Conversation;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.core.Interpolator;
+import org.jboss.seam.core.Manager;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.navigation.ConversationIdParameter;
+import org.jboss.seam.navigation.Pages;
+import org.jboss.seam.pageflow.Pageflow;
+
+/**
+ * An extended conversation manager for the JSF environment.
+ *
+ * @author Gavin King
+ * @author <a href="mailto:theute at jboss.org">Thomas Heute</a>
+ */
+ at Scope(ScopeType.EVENT)
+ at Name("org.jboss.seam.core.manager")
+ at Install(precedence=FRAMEWORK, classDependencies="javax.faces.context.FacesContext")
+ at BypassInterceptors
+public class FacesManager extends Manager
+{
+   private static final LogProvider log = Logging.getLogProvider(FacesManager.class);
+   
+   
+
+   private boolean controllingRedirect; 
+   
+   /**
+    * Temporarily promote a temporary conversation to
+    * a long running conversation for the duration of
+    * a browser redirect. After the redirect, the 
+    * conversation will be demoted back to a temporary
+    * conversation. Handle any changes to the conversation
+    * id, due to propagation via natural id.
+    */
+   public void beforeRedirect(String viewId)
+   {
+      beforeRedirect();
+      
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      String currentViewId = Pages.getViewId(facesContext);
+      if ( viewId!=null && currentViewId!=null )
+      {
+         ConversationIdParameter currentPage = Pages.instance().getPage(currentViewId).getConversationIdParameter();
+         ConversationIdParameter targetPage = Pages.instance().getPage(viewId).getConversationIdParameter();
+         if ( isDifferentConversationId(currentPage, targetPage) )
+         {
+            updateCurrentConversationId( targetPage.getConversationId() );
+         }      
+      }
+   }
+
+   public void interpolateAndRedirect(String url)
+   {
+      Map<String, Object> parameters = new HashMap<String, Object>();
+      int loc = url.indexOf('?');
+      if (loc>0)
+      {
+         StringTokenizer tokens = new StringTokenizer( url.substring(loc), "?=&" );
+         while ( tokens.hasMoreTokens() )
+         {
+            String name = tokens.nextToken();
+            String value = Interpolator.instance().interpolate( tokens.nextToken() );
+            parameters.put(name, value);
+         }
+         url = url.substring(0, loc);
+      }
+      redirect(url, parameters, true, true);
+   }
+   
+   @Override
+   protected void storeConversationToViewRootIfNecessary()
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if ( facesContext!=null && FacesLifecycle.getPhaseId()==PhaseId.RENDER_RESPONSE )
+      {
+         FacesPage.instance().storeConversation();
+      }
+   }
+
+   @Override
+   protected String generateInitialConversationId()
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      String viewId = Pages.getViewId(facesContext);
+      if ( viewId!=null )
+      {
+         return Pages.instance().getPage(viewId)
+                     .getConversationIdParameter()
+                     .getInitialConversationId( facesContext.getExternalContext().getRequestParameterMap() );
+      }
+      else
+      {
+         return super.generateInitialConversationId();
+      }
+   }
+
+   public void redirectToExternalURL(String url) {
+       try {
+           FacesContext.getCurrentInstance().getExternalContext().redirect(url);
+       } catch (IOException e) {
+          throw new RedirectException(e);
+       }
+   }
+   
+   /**
+    * Redirect to the given view id, encoding the conversation id
+    * into the request URL.
+    * 
+    * @param viewId the JSF view id
+    */
+   @Override
+   public void redirect(String viewId)
+   {
+      redirect(viewId, null, true, true);
+   }   
+   
+   public void redirect(String viewId, Map<String, Object> parameters, 
+         boolean includeConversationId)
+   {
+      redirect(viewId, parameters, includeConversationId, true);
+   }
+   
+   /**
+    * Redirect to the given view id, after encoding parameters and conversation  
+    * id into the request URL.
+    * 
+    * @param viewId the JSF view id
+    * @param parameters request parameters to be encoded (possibly null)
+    * @param includeConversationId determines if the conversation id is to be encoded
+    */
+   public void redirect(String viewId, Map<String, Object> parameters, 
+            boolean includeConversationId, boolean includePageParams)
+   {
+      if (viewId == null)
+      {
+         throw new RedirectException("cannot redirect to a null viewId");
+      }
+      FacesContext context = FacesContext.getCurrentInstance();
+      String url = context.getApplication().getViewHandler().getActionURL(context, viewId);
+      if (parameters!=null) 
+      {
+         url = encodeParameters(url, parameters);
+      }
+      
+      if (includePageParams)
+      {
+         url = Pages.instance().encodePageParameters(FacesContext.getCurrentInstance(), 
+                  url, viewId, parameters==null ? Collections.EMPTY_SET : parameters.keySet());
+      }
+      
+      if (includeConversationId)
+      {
+         beforeRedirect(viewId);
+         url = encodeConversationId(url, viewId);
+      }
+      redirect(viewId, context, url);
+   }
+   
+   /**
+    * Redirect to the given view id, after encoding the given conversation  
+    * id into the request URL.
+    * 
+    * @param viewId the JSF view id
+    * @param conversationId an id of a long-running conversation
+    */
+   @Override
+   public void redirect(String viewId, String conversationId)
+   {
+      if (viewId == null)
+      {
+         throw new RedirectException("cannot redirect to a null viewId");
+      }
+      FacesContext context = FacesContext.getCurrentInstance();
+      String url = context.getApplication().getViewHandler().getActionURL(context, viewId);
+      url = encodeConversationId(url, viewId, conversationId);
+      redirect(viewId, context, url);
+   }
+   
+   private void redirect(String viewId, FacesContext context, String url)
+   {
+      url = Pages.instance().encodeScheme(viewId, context, url);
+      if ( log.isDebugEnabled() )
+      {
+         log.debug("redirecting to: " + url);
+      }
+      ExternalContext externalContext = context.getExternalContext();
+      controllingRedirect = true;
+      try
+      {  
+         Contexts.getEventContext().set(REDIRECT_FROM_MANAGER, "");
+         externalContext.redirect( externalContext.encodeActionURL(url) );
+      }
+      catch (IOException ioe)
+      {
+         throw new RedirectException(ioe);
+      }
+      finally
+      {
+         Contexts.getEventContext().remove(REDIRECT_FROM_MANAGER);
+         controllingRedirect = false;
+      }
+      context.responseComplete();
+   }
+   
+   /**
+    * Called by the Seam Redirect Filter when a redirect is called.
+    * Appends the conversationId parameter if necessary.
+    * 
+    * @param url the requested URL
+    * @return the resulting URL with the conversationId appended
+    */
+   public String appendConversationIdFromRedirectFilter(String url, String viewId)
+   {
+      boolean appendConversationId = !controllingRedirect;
+      if (appendConversationId)
+      {
+         beforeRedirect(viewId);         
+         url = encodeConversationId(url, viewId);
+      }
+      return url;
+   }
+
+   /**
+    * If a page description is defined, remember the description and
+    * view id for the current page, to support conversation switching.
+    * Called just before the render phase.
+    */
+   public void prepareBackswitch(FacesContext facesContext) 
+   {
+      
+      Conversation conversation = Conversation.instance();
+
+      //stuff from jPDL takes precedence
+      org.jboss.seam.pageflow.Page page = 
+            Manager.instance().isLongRunningConversation() &&
+            Init.instance().isJbpmInstalled() && 
+            Pageflow.instance().isInProcess() && Pageflow.instance().isStarted() ?
+                  Pageflow.instance().getPage() : null;
+      
+      if (page==null)
+      {
+         //handle stuff defined in pages.xml
+         Pages pages = Pages.instance();
+         if (pages!=null) //for tests
+         {
+            String viewId = Pages.getViewId(facesContext);
+            org.jboss.seam.navigation.Page pageEntry = pages.getPage(viewId);
+            if ( pageEntry.isSwitchEnabled() )
+            {
+               conversation.setViewId(viewId);
+            }
+            if ( pageEntry.hasDescription() )
+            {
+               conversation.setDescription( pageEntry.renderDescription() );
+            }
+            else if(pages.hasDescription(viewId))
+            {
+               conversation.setDescription( pages.renderDescription(viewId) );  
+            }
+            conversation.setTimeout( pages.getTimeout(viewId) );
+            conversation.setConcurrentRequestTimeout( pages.getConcurrentRequestTimeout(viewId) );
+         }
+      }
+      else
+      {
+         //use stuff from the pageflow definition
+         if ( page.isSwitchEnabled() )
+         {
+            conversation.setViewId( Pageflow.instance().getPageViewId() );
+         }
+         if ( page.hasDescription() )
+         {
+            conversation.setDescription( page.getDescription() );
+         }
+         conversation.setTimeout( page.getTimeout() );
+      }
+      
+      flushConversationMetadata();
+
+   }
+
+   public static FacesManager instance()
+   {
+      return (FacesManager) Manager.instance();
+   }
+
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesMessages.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesMessages.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesMessages.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,356 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.international.StatusMessage;
+import org.jboss.seam.international.StatusMessages;
+import org.jboss.seam.util.Strings;
+
+/**
+ * A Seam component that propagates FacesMessages across redirects
+ * and interpolates EL expressions in the message string.
+ * 
+ * @author Gavin King
+ * @author Pete Muir
+ */
+ at Scope(ScopeType.CONVERSATION)
+ at Name(StatusMessages.COMPONENT_NAME)
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+ at BypassInterceptors
+public class FacesMessages extends StatusMessages
+{
+   
+   /**
+    * Called by Seam to transfer messages from FacesMessages to JSF
+    */
+   public void beforeRenderResponse() 
+   {
+      for (StatusMessage statusMessage: getMessages())
+      {
+         FacesContext.getCurrentInstance().addMessage( null, toFacesMessage(statusMessage) );
+      }
+      for ( Map.Entry<String, List<StatusMessage>> entry: getKeyedMessages().entrySet() )
+      {
+         for ( StatusMessage statusMessage: entry.getValue() )
+         {
+            String clientId = getClientId(entry.getKey());
+            FacesContext.getCurrentInstance().addMessage( clientId, toFacesMessage(statusMessage) );
+         }
+      }
+      clear();
+   }
+   
+   /**
+    * Called by Seam to transfer any messages added in the phase just processed
+    * to the FacesMessages component.
+    * 
+    * A task runner is used to allow the messages access to outjected values.
+    */
+   public static void afterPhase()
+   {
+      runTasks();
+   }
+   
+   /**
+    * Convert a StatusMessage to a FacesMessage
+    */
+   private static FacesMessage toFacesMessage(StatusMessage statusMessage)
+   {
+      if (!Strings.isEmpty(statusMessage.getSummary()))
+      {
+         return new FacesMessage(toSeverity(statusMessage.getSeverity()), statusMessage.getSummary(), statusMessage.getDetail() );
+      }
+      else
+      {
+         return null;
+      }
+   }
+   
+   /**
+    * Convert a StatusMessage.Severity to a FacesMessage.Severity
+    */
+   private static javax.faces.application.FacesMessage.Severity toSeverity(org.jboss.seam.international.StatusMessage.Severity severity)
+   {
+      switch (severity)
+      {
+      case ERROR:
+         return FacesMessage.SEVERITY_ERROR;
+      case FATAL:
+         return FacesMessage.SEVERITY_FATAL;
+      case INFO:
+         return FacesMessage.SEVERITY_INFO;
+      case WARN:
+         return FacesMessage.SEVERITY_WARN;
+      default:
+         return null;
+      }
+   }
+   
+   /**
+    * Convert a FacesMessage.Severity to a StatusMessage.Severity
+    */
+   private static org.jboss.seam.international.StatusMessage.Severity toSeverity(javax.faces.application.FacesMessage.Severity severity)
+   {
+      if (FacesMessage.SEVERITY_ERROR.equals(severity))
+      {
+         return org.jboss.seam.international.StatusMessage.Severity.ERROR;
+      }
+      else if (FacesMessage.SEVERITY_FATAL.equals(severity))
+      {
+         return org.jboss.seam.international.StatusMessage.Severity.FATAL;
+      }
+      else if (FacesMessage.SEVERITY_INFO.equals(severity))
+      {
+         return org.jboss.seam.international.StatusMessage.Severity.INFO;
+      }
+      else if (FacesMessage.SEVERITY_WARN.equals(severity))
+      {
+         return org.jboss.seam.international.StatusMessage.Severity.WARN;
+      }
+      else
+      {
+         return null;
+      }
+   }
+   
+   /**
+    * Calculate the JSF client ID from the provided widget ID
+    */
+   private String getClientId(String id)
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      return getClientId( facesContext.getViewRoot(), id, facesContext);
+   }
+
+   private static String getClientId(UIComponent component, String id, FacesContext facesContext)
+   {
+      String componentId = component.getId();
+      if (componentId!=null && componentId.equals(id))
+      {
+         return component.getClientId(facesContext);
+      }
+      else
+      {
+         Iterator iter = component.getFacetsAndChildren();
+         while ( iter.hasNext() )
+         {
+            UIComponent child = (UIComponent) iter.next();
+            String clientId = getClientId(child, id, facesContext);
+            if (clientId!=null) return clientId;
+         }
+         return null;
+      }
+   }
+   
+   /**
+    * Get all faces messages that have already been added
+    * to the context.
+    * 
+    */
+   public List<FacesMessage> getCurrentMessages()
+   {
+      List<FacesMessage> result = new ArrayList<FacesMessage>();
+      Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages();
+      while ( iter.hasNext() )
+      {
+         result.add( iter.next() );
+      }
+      return result;
+   }
+   
+   /**
+    * Get all faces global messages that have already been added
+    * to the context.
+    * 
+    */
+   public List<FacesMessage> getCurrentGlobalMessages()
+   {
+      List<FacesMessage> result = new ArrayList<FacesMessage>();
+      Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages(null);
+      while ( iter.hasNext() )
+      {
+         result.add( iter.next() );
+      }
+      return result;
+   }
+   
+   /**
+    * Get all faces messages that have already been added
+    * to the control.
+    * 
+    */
+   public List<FacesMessage> getCurrentMessagesForControl(String id)
+   {
+      String clientId = getClientId(id);
+      List<FacesMessage> result = new ArrayList<FacesMessage>();
+      Iterator<FacesMessage> iter = FacesContext.getCurrentInstance().getMessages(clientId);
+      while ( iter.hasNext() )
+      {
+         result.add( iter.next() );
+      }
+      return result;
+   }
+   
+   /**
+    * Utility method to create a FacesMessage from a Severity, messageTemplate 
+    * and params.
+    * 
+    * This method interpolates the parameters provided
+    */
+   public static FacesMessage createFacesMessage(javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
+   {
+      return createFacesMessage(severity, null, messageTemplate, params);
+   }
+   
+   /**
+    * Utility method to create a FacesMessage from a Severity, key, 
+    * defaultMessageTemplate and params.
+    * 
+    * This method interpolates the parameters provided
+    */
+   public static FacesMessage createFacesMessage(javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
+   {
+      StatusMessage message = new StatusMessage(toSeverity(severity), key, null, defaultMessageTemplate, null);
+      message.interpolate(params);
+      return toFacesMessage(message);
+   }
+   
+   /**
+    * Add a FacesMessage that will be used
+    * the next time a page is rendered.
+    * 
+    * Deprecated, use a method in {@link StatusMessages} instead
+    */
+   @Deprecated
+   public void add(FacesMessage facesMessage) 
+   {
+      if (facesMessage!=null)
+      {
+         add(toSeverity(facesMessage.getSeverity()), null, null, facesMessage.getSummary(), facesMessage.getDetail());
+      }
+   }
+   
+   /**
+    * Create a new status message, with the messageTemplate is as the message.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    * Deprecated, use {@link #add(org.jboss.seam.international.StatusMessage.Severity, String, Object...)} 
+    * instead
+    */
+   @Deprecated
+   public void add(javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
+   {
+      add(toSeverity(severity), messageTemplate, params);
+   }
+   
+   
+   /**
+    * Create a new status message, with the messageTemplate is as the message.
+    *
+    * A severity of INFO will be used, and you can specify paramters to be
+    * interpolated
+    * 
+    * Deprecated, use {@link #addToControl(String, org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
+    * instead
+    */
+   @Deprecated
+   public void addToControl(String id, javax.faces.application.FacesMessage.Severity severity, String messageTemplate, Object... params)
+   {
+      addToControl(id, toSeverity(severity), messageTemplate, params);
+   }
+   
+   /**
+    * Add a status message, looking up the message in the resource bundle
+    * using the provided key.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    * Deprecated, use {@link #addFromResourceBundle(org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
+    * instead
+    */
+   @Deprecated
+   public void addFromResourceBundle(javax.faces.application.FacesMessage.Severity severity, String key, Object... params)
+   {
+      addFromResourceBundle(toSeverity(severity), key, params);
+   }
+   
+   /**
+    * Add a status message, looking up the message in the resource bundle
+    * using the provided key.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    * Deprecated, use {@link #addFromResourceBundleOrDefault(javax.faces.application.FacesMessage.Severity, String, String, Object...)}
+    * instead
+    */
+   @Deprecated
+   public void addFromResourceBundleOrDefault(javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
+   {
+      addFromResourceBundleOrDefault(toSeverity(severity), key, defaultMessageTemplate, params);
+   }
+   
+   /**
+    * Create a new status message, looking up the message in the resource bundle
+    * using the provided key.
+    * 
+    * The message will be added to the widget specified by the ID. The algorithm
+    * used determine which widget the id refers to is determined by the view 
+    * layer implementation in use.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    * Deprecated, use {@link #addToControlFromResourceBundle(String, org.jboss.seam.international.StatusMessage.Severity, String, Object...)}
+    * instead
+    */
+   @Deprecated
+   public void addToControlFromResourceBundle(String id, javax.faces.application.FacesMessage.Severity severity, String key, Object... params)
+   {
+      addToControlFromResourceBundle(id, toSeverity(severity), key, params);
+   }
+   
+   /**
+    * Add a status message, looking up the message in the resource bundle
+    * using the provided key. If the message is found, it is used, otherwise, 
+    * the defaultMessageTemplate will be used.
+    * 
+    * The message will be added to the widget specified by the ID. The algorithm
+    * used determine which widget the id refers to is determined by the view 
+    * layer implementation in use.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    * Deprecated, use {@link #addToControlFromResourceBundleOrDefault(String, org.jboss.seam.international.StatusMessage.Severity, String, String, Object...)}
+    * instead
+    */
+   @Deprecated
+   public void addToControlFromResourceBundleOrDefault(String id, javax.faces.application.FacesMessage.Severity severity, String key, String defaultMessageTemplate, Object... params)
+   {
+      addToControlFromResourceBundleOrDefault(id, toSeverity(severity), key, defaultMessageTemplate, params);
+   }
+   
+   public static FacesMessages instance()
+   {
+      if ( !Contexts.isConversationContextActive() )
+      {
+         throw new IllegalStateException("No active conversation context");
+      }
+      return (FacesMessages) Component.getInstance(StatusMessages.COMPONENT_NAME, ScopeType.CONVERSATION);
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesPage.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesPage.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/FacesPage.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,173 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.io.Serializable;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.core.Manager;
+import org.jboss.seam.pageflow.Pageflow;
+import org.jboss.seam.web.Session;
+
+/**
+ * Book-keeping component that persists information
+ * about the conversation associated with the current
+ * page.
+ * 
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.faces.facesPage")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+ at Scope(ScopeType.PAGE)
+public class FacesPage implements Serializable
+{
+   private static final long serialVersionUID = 4807114041808347239L;
+   private String pageflowName;
+   private Integer pageflowCounter;
+   private String pageflowNodeName;
+   
+   private String conversationId;
+   private boolean conversationIsLongRunning;
+   
+   //private Map<String, Object> pageParameters;
+   
+   public String getConversationId()
+   {
+      return conversationId;
+   }
+   
+   public void discardTemporaryConversation()
+   {
+      conversationId = null;
+      conversationIsLongRunning = false;
+   }
+   
+   public void discardNestedConversation(String outerConversationId)
+   {
+      conversationId = outerConversationId;
+      conversationIsLongRunning = true;
+   }
+   
+   public void storeConversation(String conversationId)
+   {
+      this.conversationId = conversationId;
+      conversationIsLongRunning = true;
+   }
+   
+   public void storePageflow()
+   {
+      if ( Init.instance().isJbpmInstalled() )
+      {
+         Pageflow pageflow = Pageflow.instance();
+         if ( pageflow.isInProcess() /*&& !pageflow.getProcessInstance().hasEnded()*/ && Manager.instance().isLongRunningConversation() )
+         {
+            pageflowName = pageflow.getSubProcessInstance().getProcessDefinition().getName();
+            pageflowNodeName = pageflow.getNode().getName();
+            pageflowCounter = pageflow.getPageflowCounter();
+         }
+         else
+         {
+            pageflowName = null;
+            pageflowNodeName = null;
+            pageflowCounter = null;
+         }
+      }
+   }
+
+   public static FacesPage instance()
+   {
+      if ( !Contexts.isPageContextActive() )
+      {
+         throw new IllegalStateException("No page context active");
+      }
+      return (FacesPage) Component.getInstance(FacesPage.class, ScopeType.PAGE);
+   }
+
+   public boolean isConversationLongRunning()
+   {
+      return conversationIsLongRunning;
+   }
+
+   public Integer getPageflowCounter()
+   {
+      return pageflowCounter;
+   }
+
+   public String getPageflowName()
+   {
+      return pageflowName;
+   }
+
+   public String getPageflowNodeName()
+   {
+      return pageflowNodeName;
+   }
+
+   public void storeConversation()
+   {
+      Manager manager = Manager.instance();
+      
+      //we only need to execute this code when we are in the 
+      //RENDER_RESPONSE phase, ie. not before redirects
+   
+      Session session = Session.getInstance();
+      boolean sessionInvalid = session!=null && session.isInvalid();
+      if ( !sessionInvalid && manager.isLongRunningConversation() )
+      {
+         storeConversation( manager.getCurrentConversationId() );
+      }
+      else if ( !sessionInvalid && manager.isNestedConversation() )
+      {
+         discardNestedConversation( manager.getParentConversationId() );
+      }
+      else
+      {
+         discardTemporaryConversation();
+      }
+
+      /*if ( !sessionInvalid && Init.instance().isClientSideConversations()  )
+      {
+         // if we are using client-side conversations, put the
+         // map containing the conversation context variables 
+         // into the view root (or remove it for a temp 
+         // conversation context)
+         Contexts.getConversationContext().flush();
+      }*/
+
+   }
+
+   /*public Map<String, Object> getPageParameters()
+   {
+      return pageParameters==null ? Collections.EMPTY_MAP : pageParameters;
+   }
+
+   public void setPageParameters(Map<String, Object> pageParameters)
+   {
+      this.pageParameters = pageParameters.isEmpty() ? null : pageParameters;
+   }
+   
+   /**
+    * Used by test harness
+    * 
+    * @param name the page parameter name
+    * @param value the value
+    */
+   /*public void setPageParameter(String name, Object value)
+   {
+      if (pageParameters==null)
+      {
+         pageParameters = new HashMap<String, Object>();
+      }
+      pageParameters.put(name, value);
+   }*/
+
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/HttpError.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/HttpError.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/HttpError.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,76 @@
+//$Id: HttpError.java 5350 2007-06-20 17:53:19Z gavin $
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.io.IOException;
+
+import javax.faces.context.FacesContext;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.contexts.Contexts;
+
+/**
+ * Convenient HTTP errors
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.APPLICATION)
+ at BypassInterceptors
+ at Name("org.jboss.seam.faces.httpError")
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+public class HttpError
+{
+   /**
+    * Send a HTTP error as the response
+    */
+   public void send(int code)
+   {
+      try
+      {
+         getResponse().sendError(code);
+      }
+      catch (IOException ioe)
+      {
+         throw new IllegalStateException(ioe);
+      }
+      FacesContext.getCurrentInstance().responseComplete();
+   }
+
+   /**
+    * Send a HTTP error as the response
+    */
+   public void send(int code, String message)
+   {
+      try
+      {
+         getResponse().sendError(code, message);
+      }
+      catch (IOException ioe)
+      {
+         throw new IllegalStateException(ioe);
+      }
+      FacesContext.getCurrentInstance().responseComplete();
+   }
+
+   private static HttpServletResponse getResponse()
+   {
+      return (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
+   }
+
+   public static HttpError instance()
+   {
+      if ( !Contexts.isApplicationContextActive() )
+      {
+         throw new IllegalStateException("No active application scope");
+      }
+      return (HttpError) Component.getInstance(HttpError.class, ScopeType.APPLICATION);
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/IsUserInRole.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/IsUserInRole.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/IsUserInRole.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,37 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * Manager component for a map of roles assigned
+ * to the current user, as exposed via the JSF
+ * ExternalContext.
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.APPLICATION)
+ at BypassInterceptors
+ at Name("org.jboss.seam.web.isUserInRole")
+ at Install(precedence=FRAMEWORK, classDependencies="javax.faces.context.FacesContext")
+public class IsUserInRole extends org.jboss.seam.web.IsUserInRole
+{
+   @Override
+   protected Boolean isUserInRole(String role)
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if ( facesContext != null ) 
+      {
+         return facesContext.getExternalContext().isUserInRole(role);
+      }
+      
+      return super.isUserInRole(role);
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Navigator.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Navigator.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Navigator.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,109 @@
+package org.jboss.seam.faces;
+
+import java.util.Map;
+
+import javax.faces.application.FacesMessage.Severity;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.navigation.Pages;
+import org.jboss.seam.util.Strings;
+
+public abstract class Navigator
+{
+   private static final LogProvider log = Logging.getLogProvider(Navigator.class);
+
+   /**
+    * Send an error.
+    */
+   protected void error(int code, String message)
+   {
+      if ( log.isDebugEnabled() ) log.debug("sending error: " + code);
+      org.jboss.seam.faces.HttpError httpError = org.jboss.seam.faces.HttpError.instance();
+      if (message==null)
+      {
+         httpError.send(code);
+      }
+      else
+      {
+         httpError.send(code, message);
+      }
+   }
+
+   protected void redirectExternal(String url) {
+       FacesManager.instance().redirectToExternalURL(url);
+   }
+   
+   protected void redirect(String viewId, Map<String, Object> parameters)
+   {
+      redirect(viewId, parameters, true);
+   }
+   
+   /**
+    * Redirect to the view id.
+    */
+   protected void redirect(String viewId, Map<String, Object> parameters, boolean includePageParams)
+   {
+      if ( Strings.isEmpty(viewId) )
+      {
+         viewId = Pages.getCurrentViewId();
+      }
+      if ( log.isDebugEnabled() ) log.debug("redirecting to: " + viewId);
+      FacesManager.instance().redirect(viewId, parameters, true, includePageParams);
+   }
+   
+   /**
+    * Render the view id.
+    */
+   protected void render(String viewId)
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if ( !Strings.isEmpty(viewId) )
+      {
+         UIViewRoot viewRoot = facesContext.getApplication().getViewHandler()
+               .createView(facesContext, viewId);
+         facesContext.setViewRoot(viewRoot);
+      }
+      else
+      {
+         viewId = Pages.getViewId(facesContext); //just for the log message
+      }
+      if ( log.isDebugEnabled() ) log.debug("rendering: " + viewId);
+      facesContext.renderResponse();
+   }
+
+   protected static String getDisplayMessage(Exception e, String message)
+   {
+      if ( Strings.isEmpty(message) && e.getMessage()!=null ) 
+      {
+         return e.getMessage();
+      }
+      else
+      {
+         return message;
+      }
+   }
+   
+   @SuppressWarnings("deprecation")
+   protected static void addFacesMessage(String message, Severity severity, String control, Object... params)
+   {
+      if ( Contexts.isConversationContextActive() )
+      {
+         if ( !Strings.isEmpty(message) )
+         {
+            if ( Strings.isEmpty(control) )
+            {
+               FacesMessages.instance().add(severity, message, params);
+            }
+            else
+            {
+               FacesMessages.instance().addToControl(control, severity, message, params);
+            }
+         }
+      }
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Parameters.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Parameters.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Parameters.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,67 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import java.util.Map;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * Access to request parameters in the JSF environment.
+ * 
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.web.parameters")
+ at BypassInterceptors
+ at Scope(ScopeType.STATELESS)
+ at Install(precedence=FRAMEWORK, classDependencies="javax.faces.context.FacesContext")
+public class Parameters extends org.jboss.seam.web.Parameters
+{
+
+   @Override
+   protected Object convertRequestParameter(String requestParameter, Class type)
+   {
+      if ( String.class.equals(type) ) return requestParameter;
+   
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if (facesContext==null)
+      {
+         throw new IllegalStateException("No FacesContext associated with current thread, cannot convert request parameter type");
+      }
+      else
+      {
+         Converter converter = facesContext.getApplication().createConverter(type);
+         if (converter==null)
+         {
+            throw new IllegalArgumentException("no converter for type: " + type);
+         }
+         UIViewRoot viewRoot = facesContext.getViewRoot();
+         return converter.getAsObject( 
+                  facesContext, 
+                  viewRoot==null ? new UIViewRoot() : viewRoot, //have to pass something here, or get a totally useless NPE from JSF 
+                  requestParameter );
+      }
+   }
+
+   @Override
+   public Map<String, String[]> getRequestParameters()
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if ( facesContext != null )
+      {
+         return facesContext.getExternalContext().getRequestParameterValuesMap();
+      }
+      
+      return super.getRequestParameters();
+   }
+
+}

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

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/RedirectException.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/RedirectException.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/RedirectException.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,17 @@
+package org.jboss.seam.faces;
+
+import java.io.IOException;
+
+public class RedirectException extends RuntimeException
+{
+
+   public RedirectException(IOException ioe)
+   {
+      super(ioe);
+   }
+   
+   public RedirectException(String message)
+   {
+      super(message);
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Renderer.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Renderer.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Renderer.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,23 @@
+package org.jboss.seam.faces;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+
+/**
+ * A component for direct rendering of
+ * templates. Especially useful with
+ * Seam Mail. 
+ *
+ */
+ at Name("org.jboss.seam.faces.renderer")
+ at Install(false)
+public abstract class Renderer
+{
+    public abstract String render(String viewId);
+    
+    public static Renderer instance()
+    {
+        return (Renderer) Component.getInstance(Renderer.class);
+    }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/ResourceLoader.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/ResourceLoader.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/ResourceLoader.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,56 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.util.FacesResources;
+
+/**
+ * Access to application resources in tye JSF environment.
+ * 
+ * @author Gavin King
+ *
+ */
+ at Scope(ScopeType.STATELESS)
+ at BypassInterceptors
+ at Install(precedence=FRAMEWORK, classDependencies="javax.faces.context.FacesContext")
+ at Name("org.jboss.seam.core.resourceLoader")
+public class ResourceLoader extends org.jboss.seam.core.ResourceLoader
+{
+   
+   @Override
+   public InputStream getResourceAsStream(String resource)
+   {
+      javax.faces.context.FacesContext context = javax.faces.context.FacesContext.getCurrentInstance();
+      if (context!=null)
+      {
+         return FacesResources.getResourceAsStream( resource, context.getExternalContext() );
+      }
+      else
+      {
+         return super.getResourceAsStream(resource);
+      }
+   }
+
+   @Override
+   public URL getResource(String resource) 
+   {
+      javax.faces.context.FacesContext context = javax.faces.context.FacesContext.getCurrentInstance();
+      if (context!=null)
+      {
+         return FacesResources.getResource( resource, context.getExternalContext() );
+      }
+      else
+      {
+         return super.getResource(resource);
+      }
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Selector.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Selector.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Selector.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,122 @@
+package org.jboss.seam.faces;
+
+import java.io.Serializable;
+
+import javax.faces.context.FacesContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jboss.seam.core.AbstractMutable;
+
+/**
+ * Support for selector objects which remember their selection as a cookie
+ * 
+ * @author Gavin King
+ */
+public abstract class Selector extends AbstractMutable implements Serializable
+{
+   public static final int DEFAULT_MAX_AGE = 31536000; // 1 year in seconds
+   private boolean cookieEnabled;
+   private int cookieMaxAge = DEFAULT_MAX_AGE;
+   private String cookiePath= "/";
+   
+   /**
+    * Is the cookie enabled?
+    * @return false by default
+    */
+   public boolean isCookieEnabled()
+   {
+      return cookieEnabled;
+   }
+   public void setCookieEnabled(boolean cookieEnabled)
+   {
+      setDirty(this.cookieEnabled, cookieEnabled);
+      this.cookieEnabled = cookieEnabled;
+   }
+   /**
+    * The max age of the cookie
+    * @return 1 year by default
+    */
+   public int getCookieMaxAge()
+   {
+      return cookieMaxAge;
+   }
+   public void setCookieMaxAge(int cookieMaxAge)
+   {
+      this.cookieMaxAge = cookieMaxAge;
+   }
+   
+   public String getCookiePath()
+   {
+      return cookiePath;
+   }
+   
+   public void setCookiePath(String cookiePath)
+   {
+      this.cookiePath = cookiePath;
+   }
+   
+   /**
+    * Override to define the cookie name
+    */
+   protected abstract String getCookieName();
+   
+   /**
+    * Get the value of the cookie
+    */
+   protected String getCookieValueIfEnabled()
+   {
+      return isCookieEnabled() ?
+         getCookieValue() : null;
+   }
+   
+   protected Cookie getCookie()
+   {
+      FacesContext ctx = FacesContext.getCurrentInstance();
+      if (ctx != null)
+      {
+          return (Cookie) ctx.getExternalContext().getRequestCookieMap()
+            .get( getCookieName() );
+      }
+      else
+      {
+         return null;
+      }
+   }
+   
+   protected String getCookieValue()
+   {
+      Cookie cookie = getCookie();
+      return cookie==null ? null : cookie.getValue();
+   }
+   
+   protected void clearCookieValue()
+   {
+      Cookie cookie = getCookie();
+      if ( cookie!=null )
+      {
+         HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();         
+         cookie.setValue(null);
+         cookie.setPath(cookiePath);
+         cookie.setMaxAge(0);
+         response.addCookie(cookie);
+      }
+   }
+   
+   /**
+    * Set the cookie
+    */
+   protected void setCookieValueIfEnabled(String value)
+   {
+      FacesContext ctx = FacesContext.getCurrentInstance();
+      
+      if ( isCookieEnabled() && ctx != null)
+      {
+         HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
+         Cookie cookie = new Cookie( getCookieName(), value );
+         cookie.setMaxAge( getCookieMaxAge() );
+         cookie.setPath(cookiePath);
+         response.addCookie(cookie);
+      }
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Switcher.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Switcher.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Switcher.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,125 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.faces.model.SelectItem;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.core.ConversationEntries;
+import org.jboss.seam.core.ConversationEntry;
+import org.jboss.seam.core.Manager;
+import org.jboss.seam.web.Session;
+
+/**
+ * Support for the conversation switcher drop-down menu.
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.PAGE)
+ at Name("org.jboss.seam.faces.switcher")
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+ at BypassInterceptors
+public class Switcher implements Serializable 
+{
+   
+   private static final long serialVersionUID = -6403911073853051938L;
+   private List<SelectItem> selectItems;
+   private String conversationIdOrOutcome;
+   private String resultingConversationIdOrOutcome;
+      
+   @Create
+   public void createSelectItems()
+   {
+      ConversationEntries conversationEntries = ConversationEntries.getInstance();
+      if (conversationEntries==null)
+      {
+         selectItems = Collections.EMPTY_LIST;
+      }
+      else
+      {
+         Set<ConversationEntry> orderedEntries = new TreeSet<ConversationEntry>();
+         orderedEntries.addAll( conversationEntries.getConversationEntries() );
+         selectItems = new ArrayList<SelectItem>( conversationEntries.size() );
+         for ( ConversationEntry entry: orderedEntries )
+         {
+            if ( entry.isDisplayable() && !Session.instance().isInvalid() )
+            {
+               selectItems.add( new SelectItem( entry.getId(), entry.getDescription() ) );
+            }
+         }
+      }
+   }
+   
+   public List<SelectItem> getSelectItems()
+   {
+      return selectItems;
+   }
+      
+   private String getLongRunningConversationId()
+   {
+      Manager manager = Manager.instance();
+      if ( manager.isLongRunningConversation() )
+      {
+         return manager.getCurrentConversationId();
+      }
+      else if ( manager.isNestedConversation() )
+      {
+         return manager.getParentConversationId();
+      }
+      else
+      {
+         //TODO: is there any way to set it to the current outcome, instead of null?
+         return null;
+      }
+   }
+
+   public String getConversationIdOrOutcome() 
+   {
+      return resultingConversationIdOrOutcome==null ? 
+            getLongRunningConversationId() :
+            resultingConversationIdOrOutcome;
+   }
+
+   public void setConversationIdOrOutcome(String selectedId) 
+   {
+      this.conversationIdOrOutcome = selectedId;
+   }
+   
+   public String select()
+   {
+
+      boolean isOutcome = conversationIdOrOutcome==null || 
+                    (!Character.isDigit(conversationIdOrOutcome.charAt(0)) && conversationIdOrOutcome.indexOf(':') < 0);       
+      
+      String actualOutcome;
+      if (isOutcome)
+      {
+         resultingConversationIdOrOutcome = conversationIdOrOutcome;
+         actualOutcome = conversationIdOrOutcome;
+      }
+      else
+      {
+         ConversationEntry ce = ConversationEntries.instance().getConversationEntry(conversationIdOrOutcome);
+         if (ce!=null)
+         {
+            resultingConversationIdOrOutcome = ce.getId();
+            ce.redirect();
+         }
+         actualOutcome = null;
+      }
+      return actualOutcome;
+   }
+  
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/UiComponent.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/UiComponent.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/UiComponent.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,81 @@
+package org.jboss.seam.faces;
+
+import static org.jboss.seam.ScopeType.STATELESS;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * Access to UIComponents in the current view, by id.
+ * 
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.faces.uiComponent")
+ at BypassInterceptors
+ at Scope(STATELESS)
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+public class UiComponent
+{
+   
+   @Unwrap
+   public Map<String, UIComponent> getViewComponents()
+   {
+      return new AbstractMap<String, UIComponent>() 
+      {
+
+         @Override
+         public boolean containsKey(Object key) {
+            return get(key) != null;
+         }
+         
+          
+         @Override
+         public Set<Map.Entry<String, UIComponent>> entrySet()
+         {
+            throw new UnsupportedOperationException();
+         }
+
+         @Override
+         public UIComponent get(Object key)
+         {
+            if ( !(key instanceof String) ) return null;
+            try
+            {
+                FacesContext context = FacesContext.getCurrentInstance();
+
+                if (context == null) {
+                    return null;
+                }
+                
+                UIViewRoot viewRoot = context.getViewRoot();
+                
+                if (viewRoot == null)
+                {
+                   return null;
+                }
+
+                return viewRoot.findComponent( (String) key );
+            }
+            catch (IllegalArgumentException iae)
+            {
+               return null;
+            }
+         }
+         
+      };
+   }
+   
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/UserPrincipal.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/UserPrincipal.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/UserPrincipal.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,30 @@
+package org.jboss.seam.faces;
+
+import java.security.Principal;
+
+import javax.annotation.Named;
+import javax.context.ApplicationScoped;
+import javax.faces.context.FacesContext;
+
+/**
+ * Manager component for the current user Principal
+ * exposed via the JSF ExternalContext.
+ * 
+ * @author Gavin King
+ */
+ at Named
+ at ApplicationScoped
+public class UserPrincipal extends org.jboss.seam.web.UserPrincipal
+{
+   @Unwrap @Override
+   public Principal getUserPrincipal()
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if ( facesContext != null ) 
+      {
+         return facesContext.getExternalContext().getUserPrincipal();
+      }
+      
+      return super.getUserPrincipal();
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/Validation.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/Validation.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/Validation.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,51 @@
+package org.jboss.seam.faces;
+
+import javax.annotation.Named;
+import javax.faces.context.FacesContext;
+import javax.inject.Current;
+import javax.inject.manager.Manager;
+
+import org.jboss.seam.faces.events.ValidationFailedEvent;
+
+/**
+ * Allows the application to determine whether the JSF validation
+ * phase completed successfully, or if a validation failure
+ * occurred.
+ * 
+ * @author Gavin king
+ *
+ */
+ at Named
+public class Validation
+{
+   private boolean succeeded;
+   private boolean failed;
+   
+   @Current Manager manager;
+   
+   public void afterProcessValidations(FacesContext facesContext)
+   {
+      failed = facesContext.getRenderResponse();
+      if (failed)
+      {
+         manager.fireEvent(new ValidationFailedEvent());
+      }
+      succeeded = !failed;
+   }
+
+   public boolean isSucceeded()
+   {
+      return succeeded;
+   }
+
+   public boolean isFailed()
+   {
+      return failed;
+   }
+
+   public void fail()
+   {
+      failed = true;
+      succeeded = false;
+   }
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/events/ValidationFailedEvent.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/events/ValidationFailedEvent.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/events/ValidationFailedEvent.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,11 @@
+package org.jboss.seam.faces.events;
+
+/**
+ * This event is raised when JSF validation fails.
+ *  
+ * @author Shane Bryzak
+ */
+public class ValidationFailedEvent
+{
+
+}

Added: modules/trunk/faces/src/main/java/org/jboss/seam/faces/package-info.java
===================================================================
--- modules/trunk/faces/src/main/java/org/jboss/seam/faces/package-info.java	                        (rev 0)
+++ modules/trunk/faces/src/main/java/org/jboss/seam/faces/package-info.java	2009-04-23 01:09:20 UTC (rev 10601)
@@ -0,0 +1,11 @@
+/**
+ * A set of Seam components for working with JSF.
+ * Some of these components extend core components
+ * and add JSF-specific functionality. Others
+ * exist to put a friendly face to JSF.
+ */
+ at AutoCreate
+package org.jboss.seam.faces;
+
+import org.jboss.seam.annotations.AutoCreate;
+




More information about the seam-commits mailing list