org.sakaiproject.tool.gradebook.jsf
Class FacesUtil

java.lang.Object
  extended byorg.sakaiproject.tool.gradebook.jsf.FacesUtil

public class FacesUtil
extends Object

A noninstantiable utility class, because every JSF project needs one.


Field Summary
static int MAXIMUM_MEANINGFUL_DECIMAL_PLACES
          Before display, scores are rounded at this number of decimal places and later truncated to (hopefully) a shorter number.
 
Method Summary
static void addErrorMessage(String message)
          Methods to centralize our approach to messages, since we may have to adapt the default Faces implementation.
static void addMessage(String message)
           
static void addRedirectSafeMessage(String message)
          We want to use standard faces messaging for intra-page messages, such as validation checking, but we want to use the custom messaging approach for inter-page messaging.
static void addUniqueErrorMessage(String message)
           
static void clearAllInputs(UIComponent component)
          JSF 1.1 provides no way to cleanly discard input fields from a table when we know we won't use them.
static String getActionUrl(String action)
          Because POST arguments aren't carried over redirects, the easiest way to get bookmarkable URLs is to use "h:outputLink" rather than "h:commandLink" or "h:commandButton", and to add query string parameters via "f:param".
static Map getEventParameterMap(FacesEvent event)
          If the JSF h:commandLink component includes f:param children, those name-value pairs are put into the request parameter map for later use by the action handler.
static String getLocalizedString(FacesContext context, String key)
          Gets a localized message string based on the locale determined by the FacesContext.
static String getLocalizedString(String key)
          Gets a localized message string based on the locale determined by the FacesContext.
static String getLocalizedString(String key, String[] params)
          Gets a localized message string based on the locale determined by the FacesContext.
static double getRoundDown(double rawValue, int maxDecimalPlaces)
          All Faces number formatting options round instead of truncating.
static Object resolveVariable(String name)
          To cut down on configuration noise, allow access to request-scoped beans from session-scoped beans, and so on, this method lets the caller try to find anything anywhere that Faces can look for it.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

MAXIMUM_MEANINGFUL_DECIMAL_PLACES

public static int MAXIMUM_MEANINGFUL_DECIMAL_PLACES
Before display, scores are rounded at this number of decimal places and later truncated to (hopefully) a shorter number.

Method Detail

getEventParameterMap

public static final Map getEventParameterMap(FacesEvent event)
If the JSF h:commandLink component includes f:param children, those name-value pairs are put into the request parameter map for later use by the action handler. Unfortunately, the same isn't done for h:commandButton. This is a workaround to let arguments be associated with a button. Because action listeners are guaranteed to be executed before action methods, an action listener can use this method to update any context the action method might need.


resolveVariable

public static final Object resolveVariable(String name)
To cut down on configuration noise, allow access to request-scoped beans from session-scoped beans, and so on, this method lets the caller try to find anything anywhere that Faces can look for it. WARNING: If what you're looking for is a managed bean and it isn't found, it will be created as a result of this call.


getActionUrl

public static final String getActionUrl(String action)
Because POST arguments aren't carried over redirects, the easiest way to get bookmarkable URLs is to use "h:outputLink" rather than "h:commandLink" or "h:commandButton", and to add query string parameters via "f:param". However, if the value of the output link is something like "editAsg.jsf", we've introduced untestable assumptions about the local naming and navigation configurations. This method will safely return the output link value corresponding to the specified "from-outcome" view ID.


addErrorMessage

public static void addErrorMessage(String message)
Methods to centralize our approach to messages, since we may have to adapt the default Faces implementation.


addMessage

public static void addMessage(String message)

addUniqueErrorMessage

public static void addUniqueErrorMessage(String message)

addRedirectSafeMessage

public static void addRedirectSafeMessage(String message)
We want to use standard faces messaging for intra-page messages, such as validation checking, but we want to use the custom messaging approach for inter-page messaging. So, for now we're going to add the inter-page messages to the custom MessagingBean.

Parameters:
message -

clearAllInputs

public static void clearAllInputs(UIComponent component)
JSF 1.1 provides no way to cleanly discard input fields from a table when we know we won't use them. Ideally in such circumstances we'd specify an "immediate" action handler (to skip unnecessary validation checks and model updates), and then overwrite any existing values. However, JSF absolutely insists on keeping any existing input components as they are if validation and updating hasn't been done. When the table is re-rendered, all of the readonly portions of the columns will be refreshed from the backing bean, but the input fields will keep their now-incorrect values.

The easiest practical way to deal with this limitation is to avoid "immediate" actions when a table contains input fields, avoid side-effects from the bogus model updates, and stick the user with the inconvenience of unnecessary validation errors.

The only other solution we've found is to have the backing bean bind to the data table component (which just means storing a transient pointer to the UIData or HtmlDataTable when it's passed to the bean's "setTheDataTable" method), and then to have the action handler call this method to walk the table, look for UIInputs on each row, and perform the necessary magic on each to force reloading from the data model.

Usage:

   private transient HtmlDataTable dataTable;
   public HtmlDataTable getDataTable() {
     return dataTable;
   }
   public void setDataTable(HtmlDataTable dataTable) {
     this.dataTable = dataTable;
   }
   public void processImmediateIdSwitch(ActionEvent event) {
      // ... modify the current ID ...
      FacesUtil.clearAllInputs(dataTable);
   }
 


getLocalizedString

public static String getLocalizedString(FacesContext context,
                                        String key)
Gets a localized message string based on the locale determined by the FacesContext.

Parameters:
key - The key to look up the localized string

getLocalizedString

public static String getLocalizedString(String key)
Gets a localized message string based on the locale determined by the FacesContext. Useful for adding localized FacesMessages from a backing bean.

Parameters:
key - The key to look up the localized string

getLocalizedString

public static String getLocalizedString(String key,
                                        String[] params)
Gets a localized message string based on the locale determined by the FacesContext. Useful for adding localized FacesMessages from a backing bean.

Parameters:
key - The key to look up the localized string
params - The array of strings to use in replacing the placeholders in the localized string

getRoundDown

public static double getRoundDown(double rawValue,
                                  int maxDecimalPlaces)
All Faces number formatting options round instead of truncating. For the Gradebook, virtually no displayed numbers are ever supposed to round up. This method moves the specified raw value into a higher-resolution BigDecimal, rounding away noise at MAXIMUM_MEANINGFUL_DECIMAL_PLACES. It then rounds down to reach the specified maximum number of decimal places and returns the equivalent double for further formatting. This is all necessary because we don't store scores as BigDecimal and because Java / JSF lacks a DecimalFormat class which uses "floor" instead of "round" when trimming decimal places.