[seam-commits] Seam SVN: r10558 - in modules/trunk/international: src/main/java and 4 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Tue Apr 21 21:23:11 EDT 2009


Author: shane.bryzak at jboss.com
Date: 2009-04-21 21:23:11 -0400 (Tue, 21 Apr 2009)
New Revision: 10558

Added:
   modules/trunk/international/pom.xml
   modules/trunk/international/src/main/java/org/
   modules/trunk/international/src/main/java/org/jboss/
   modules/trunk/international/src/main/java/org/jboss/seam/
   modules/trunk/international/src/main/java/org/jboss/seam/international/
   modules/trunk/international/src/main/java/org/jboss/seam/international/Locale.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleConfig.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleSelector.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/Messages.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessage.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessages.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZone.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneSelector.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneWrapper.java
   modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZones.java
Modified:
   modules/trunk/international/
Log:
add international module source


Property changes on: modules/trunk/international
___________________________________________________________________
Name: svn:ignore
   + .classpath
.project
.settings
target


Added: modules/trunk/international/pom.xml
===================================================================
--- modules/trunk/international/pom.xml	                        (rev 0)
+++ modules/trunk/international/pom.xml	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,28 @@
+<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-international</artifactId>
+   <packaging>jar</packaging>
+   <version>3.0.0-SNAPSHOT</version>
+   <name>Seam Internationalisation</name>
+         
+   <dependencies>
+      <dependency>
+         <groupId>org.jboss.webbeans</groupId>
+         <artifactId>jsr299-api</artifactId>
+      </dependency>              
+      <dependency>
+         <groupId>org.jboss.webbeans</groupId>
+         <artifactId>webbeans-logging</artifactId>
+      </dependency> 
+   </dependencies>
+  
+</project>

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/Locale.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/Locale.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/Locale.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,21 @@
+package org.jboss.seam.international;
+
+import javax.annotation.Named;
+import javax.inject.Produces;
+
+/**
+ * Manager component for the current locale that is
+ * aware of the selected locale
+ * 
+ * @author Gavin King
+ */
+public class Locale extends org.jboss.seam.core.Locale
+{
+   @Produces public java.util.Locale getLocale()
+   {
+      return Contexts.isSessionContextActive() ?
+            LocaleSelector.instance().getLocale() :
+            super.getLocale();
+   }
+   
+}
\ No newline at end of file

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleConfig.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleConfig.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleConfig.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,133 @@
+package org.jboss.seam.international;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.context.ApplicationScoped;
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.inject.Initializer;
+
+import org.jboss.seam.util.Strings;
+
+/**
+ * Configures the JSF locale support from the Seam container.
+ * 
+ * <p>
+ * This component merely passes on configuration settings to the JSF runtime, so
+ * you still have to option of configure the locale support in the JSF
+ * configuration file. However, if you enable this component, it will overwrite
+ * any settings from that file.
+ * </p>
+ * 
+ * <code>
+ *   &lt;i18n:locale-config default-locale="en" supported-locales="en fr de"/&gt;
+ * </code>
+ * 
+ * @author Dan Allen
+ */
+ at ApplicationScoped
+public class LocaleConfig
+{
+   private String defaultLocale;
+
+   private List<String> supportedLocales;
+
+   @Initializer
+   public void initLocaleConfig()
+   {
+      Application application = getApplication();
+      if (application == null)
+      {
+         return;
+      }
+
+      String defaultAsString = getDefaultLocale();
+      if (defaultAsString != null)
+      {
+         application.setDefaultLocale(getLocaleFromString(defaultAsString));
+      }
+
+      List<String> supportedAsStrings = getSupportedLocales();
+      int numSupported = supportedAsStrings != null ? supportedAsStrings.size() : 0;
+      if (numSupported > 0)
+      {
+         // use set to prevent duplicates, yet retain order just to be nice
+         Set<java.util.Locale> locales = new LinkedHashSet<java.util.Locale>(numSupported);
+         for (String supportedAsString : supportedAsStrings)
+         {
+            locales.add(getLocaleFromString(supportedAsString));
+         }
+         application.setSupportedLocales(locales);
+      }
+   }
+
+   public String getDefaultLocale()
+   {
+      return defaultLocale;
+   }
+
+   public void setDefaultLocale(String defaultLocale)
+   {
+      this.defaultLocale = defaultLocale;
+   }
+
+   public List<String> getSupportedLocales()
+   {
+      return supportedLocales;
+   }
+
+   public void setSupportedLocales(List<String> supportedLocales)
+   {
+      this.supportedLocales = supportedLocales;
+   }
+
+   public static LocaleConfig instance()
+   {
+      return (LocaleConfig) Component.getInstance(LocaleConfig.class, ScopeType.APPLICATION);
+   }
+
+   private java.util.Locale getLocaleFromString(String localeString)
+   {
+      if (localeString == null || localeString.length() < 2)
+      {
+         throw new IllegalArgumentException("Invalid locale string: " + localeString);
+      }
+
+      StringTokenizer tokens = new StringTokenizer(localeString, "-_");
+      String language = tokens.hasMoreTokens() ? tokens.nextToken() : null;
+      String country = tokens.hasMoreTokens() ? tokens.nextToken() : null;
+      String variant = tokens.hasMoreTokens() ? tokens.nextToken() : null;
+      if (!Strings.isEmpty(variant))
+      {
+         return new java.util.Locale(language, country, variant);
+      }
+      else if (!Strings.isEmpty(country))
+      {
+         return new java.util.Locale(language, country);
+      }
+      else
+      {
+         return new java.util.Locale(language);
+      }
+   }
+
+   private Application getApplication()
+   {
+      try
+      {
+         ApplicationFactory factory = (ApplicationFactory) FactoryFinder
+            .getFactory(FactoryFinder.APPLICATION_FACTORY);
+         return factory.getApplication();
+      }
+      catch (IllegalStateException e)
+      {
+         // just in case, for units and the like
+         // if we can't do it, it just wan't meant to be
+         return null;
+      }
+   }
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleSelector.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleSelector.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/LocaleSelector.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,217 @@
+package org.jboss.seam.international;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import javax.faces.context.FacesContext;
+import javax.faces.event.ValueChangeEvent;
+import javax.faces.model.SelectItem;
+import javax.servlet.ServletRequest;
+
+import org.jboss.seam.Component;
+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.contexts.Contexts;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.faces.Selector;
+import org.jboss.seam.util.Strings;
+import org.jboss.seam.web.ServletContexts;
+
+/**
+ * Selects the current user's locale
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.SESSION)
+ at Name("org.jboss.seam.international.localeSelector")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+public class LocaleSelector extends Selector
+{
+   private static final long serialVersionUID = -6087667065688208261L;
+   
+   private String language;
+   private String country;
+   private String variant;
+   
+   @Create
+   public void initLocale()
+   {
+      String localeString = getCookieValueIfEnabled();
+      if (localeString!=null) setLocaleString(localeString);
+   }
+   
+   @Override
+   protected String getCookieName()
+   {
+      return "org.jboss.seam.core.Locale";
+   }
+   
+   /**
+    * Force the resource bundle to reload, using the current locale,
+    * and raise the org.jboss.seam.localeSelected event.
+    */
+   public void select()
+   {
+      FacesContext.getCurrentInstance().getViewRoot().setLocale( getLocale() );
+      //Contexts.removeFromAllContexts("org.jboss.seam.core.resourceBundle");
+      Contexts.removeFromAllContexts("org.jboss.seam.international.messages");
+      
+      setCookieValueIfEnabled( getLocaleString() );
+
+      if ( Events.exists() ) 
+      {
+          Events.instance().raiseEvent( "org.jboss.seam.localeSelected", getLocaleString() );
+      }
+   }
+   
+   public void select(ValueChangeEvent event) 
+   {
+      setLocaleString( (String) event.getNewValue() );
+      select();
+   }
+
+   /**
+    * Set the language and force resource bundle reload, useful for quick action links:
+    * <tt>&lt;h:commandLink value="DE" action="#{localeSelector.selectLanguage('de')}"/>"/></tt>
+    */
+   public void selectLanguage(String language) {
+      setLanguage(language);
+      select();
+   }
+
+   public Locale calculateLocale(Locale jsfLocale)
+   {
+      if ( !Strings.isEmpty(variant) )
+      {
+         return new java.util.Locale(language, country, variant);
+      }
+      else if ( !Strings.isEmpty(country) )
+      {
+         return new java.util.Locale(language, country);
+      }
+      else if ( !Strings.isEmpty(language) )
+      {
+         return new java.util.Locale(language);
+      }
+      else
+      {
+         return jsfLocale;
+      }
+   }
+   
+   public void setLocale(Locale locale)
+   {
+      language = Strings.nullIfEmpty( locale.getLanguage() );
+      country = Strings.nullIfEmpty( locale.getCountry() );
+      variant = Strings.nullIfEmpty( locale.getVariant() );
+   }
+   
+   public String getLocaleString()
+   {
+      return getLocale().toString();
+   }
+   
+   public void setLocaleString(String localeString)
+   {
+      StringTokenizer tokens = new StringTokenizer(localeString, "-_");
+      language = tokens.hasMoreTokens() ? tokens.nextToken() : null;
+      country =  tokens.hasMoreTokens() ? tokens.nextToken() : null;
+      variant =  tokens.hasMoreTokens() ? tokens.nextToken() : null;
+   }
+   
+   public List<SelectItem> getSupportedLocales()
+   {
+      List<SelectItem> selectItems = new ArrayList<SelectItem>();
+      Iterator<Locale> locales = FacesContext.getCurrentInstance().getApplication().getSupportedLocales();
+      while ( locales.hasNext() )
+      {
+         Locale locale = locales.next();
+         if ( !Strings.isEmpty( locale.getLanguage() ) )
+         {
+            selectItems.add( new SelectItem( locale.toString(), locale.getDisplayName(locale) ) );
+         }
+      }
+      return selectItems;
+   }
+
+   /**
+    * Get the selected locale
+    */
+   public Locale getLocale() 
+   {
+      FacesContext facesContext = FacesContext.getCurrentInstance();
+      if (facesContext!=null)
+      {
+         //Note: this does a double dispatch back to LocaleSelector.calculateLocale()
+         return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
+      }
+      
+      ServletContexts servletContexts = ServletContexts.getInstance();
+      if (servletContexts!=null)
+      {
+         ServletRequest request = servletContexts.getRequest();
+         if (request!=null)
+         {
+            return calculateLocale( request.getLocale() );
+         }
+      }
+
+      return calculateLocale( Locale.getDefault() );
+   }
+
+   public static LocaleSelector instance()
+   {
+      if ( !Contexts.isSessionContextActive() )
+      {
+         throw new IllegalStateException("No active session context");
+      }
+      return (LocaleSelector) Component.getInstance(LocaleSelector.class, ScopeType.SESSION);
+   }
+
+   public String getCountry() 
+   {
+      if (country==null) return getLocale().getCountry();
+      return country;
+   }
+
+   public void setCountry(String country) 
+   {
+      setDirty(this.country, country);
+      this.country = country;
+   }
+
+   public String getLanguage() 
+   {
+      if (language==null) return getLocale().getLanguage();
+      return language;
+   }
+
+   public void setLanguage(String language) 
+   {
+      setDirty(this.language, language);
+      this.language = language;
+   }
+
+   public String getVariant() 
+   {
+      if (variant==null) return getLocale().getVariant();
+      return variant;
+   }
+
+   public void setVariant(String variant) 
+   {
+      setDirty(this.variant, variant);
+      this.variant = variant;
+   }
+
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/Messages.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/Messages.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/Messages.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,133 @@
+package org.jboss.seam.international;
+
+import static org.jboss.seam.ScopeType.EVENT;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Set;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Factory;
+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.SeamResourceBundle;
+
+/**
+ * Factory for a Map that contains interpolated messages defined in the
+ * Seam ResourceBundle.
+ * 
+ * @see org.jboss.seam.core.SeamResourceBundle
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.STATELESS)
+ at BypassInterceptors
+ at Name("org.jboss.seam.international.messagesFactory")
+ at Install(precedence=BUILT_IN)
+public class Messages
+{
+   //TODO: now we have ELResolver, it doesn't *have* to be a Map...
+      
+   protected Map createMap() 
+   {  
+	  // AbstractMap uses the implementation of entrySet to perform all its 
+	  // operations - for a resource bundle this is very inefficient for keys
+      return new AbstractMap<String, String>()
+      {
+         private java.util.ResourceBundle bundle = SeamResourceBundle.getBundle();
+         
+         @Override
+         public String get(Object key) 
+         {
+            if (key instanceof String)
+            {
+               String resourceKey = (String) key;
+               String resource=null;
+               if (bundle!=null)
+               {
+                  try
+                  {
+                     resource = bundle.getString(resourceKey);
+                  }
+                  catch (MissingResourceException mre)
+                  {
+                     //Just swallow
+                  }
+               }
+               return resource==null ? resourceKey : resource;
+            }
+            else
+            {
+               return null;
+            }
+         }
+         
+         @Override
+         public Set<Map.Entry<String, String>> entrySet() 
+         {
+        	Enumeration<String> keys = bundle.getKeys();  
+            Map<String, String> map = new HashMap<String, String>();
+            while ( keys.hasMoreElements() )
+            {
+               String key = keys.nextElement();
+               map.put( key, get(key) );
+            }  
+            return Collections.unmodifiableSet(map.entrySet());
+         }
+
+         @Override
+         public boolean containsKey(Object key)
+         {
+            return get(key) != null;
+         }
+
+         @Override
+         public Set<String> keySet()
+         {
+            Enumeration<String> keys = bundle.getKeys();  
+            return new HashSet<String>(Collections.list(keys));
+         }
+
+         @Override
+         public int size()
+         {
+            return keySet().size();
+         }
+         
+      };
+   }
+
+   /**
+    * Create the Map and cache it in the EVENT scope. No need to cache
+    * it in the SESSION scope, since it is inexpensive to create.
+    * 
+    * @return a Map that interpolates messages in the Seam ResourceBundle
+    */
+   @Factory(value="org.jboss.seam.international.messages", autoCreate=true, scope=EVENT)
+   public Map<String, String> getMessages()
+   {
+      return createMap();
+   }
+   
+   /**
+    * @return the message Map instance
+    */
+   public static Map<String, String> instance()
+   {
+      if ( !Contexts.isSessionContextActive() )
+      {
+         throw new IllegalStateException("no event context active");
+      }
+      return (Map<String, String>) Component.getInstance("org.jboss.seam.international.messages", true);
+   }
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessage.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessage.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessage.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,122 @@
+package org.jboss.seam.international;
+
+import java.io.Serializable;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.jboss.seam.core.Interpolator;
+import org.jboss.seam.core.SeamResourceBundle;
+import org.jboss.seam.util.Strings;
+
+/**
+ * A status message which can be created in the business layer and displayed
+ * in the view layer
+ *
+ * @author Pete Muir
+ *
+ */
+public class StatusMessage implements Serializable
+{
+   
+   /**
+    * The severity of the status message
+    *
+    */
+   public enum Severity
+   {
+      INFO, 
+      WARN, 
+      ERROR, 
+      FATAL;
+   }
+   
+   private String summaryTemplate;
+   private String summary;
+   private String detailTemplate;
+   private String detail;
+   private Severity severity = Severity.INFO;
+   
+   /**
+    * Create 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.
+    * 
+    */
+   public StatusMessage(Severity severity, String key, String detailKey, String defaultMessageTemplate, String defaultMessageDetailTemplate)
+   {
+      this.summaryTemplate = getBundleMessage(key, defaultMessageTemplate);
+      this.detailTemplate = getBundleMessage(detailKey, defaultMessageDetailTemplate);
+      if ( !Strings.isEmpty(summaryTemplate) )
+      {
+         this.severity = severity;
+      }
+   }
+   
+   public boolean isEmpty()
+   {
+      return Strings.isEmpty(summary) && Strings.isEmpty(summaryTemplate);
+   }
+   
+   public void interpolate(Object... params)
+   {
+      if (!Strings.isEmpty(summaryTemplate))
+      {
+         this.summary = Interpolator.instance().interpolate(summaryTemplate, params);
+      }
+      if (!Strings.isEmpty(detailTemplate))
+      {
+         this.detail = Interpolator.instance().interpolate(detailTemplate, params);
+      }
+   }
+
+   /**
+    * Get the message
+    * 
+    */
+   public String getSummary()
+   {
+      return summary;
+   }
+   
+   /**
+    * Get the message severity
+    */
+   public Severity getSeverity()
+   {
+      return severity;
+   }
+   
+   public String getDetail()
+   {
+      return detail;
+   }
+   
+   public static String getBundleMessage(String key, String defaultMessageTemplate)
+   {
+      String messageTemplate = defaultMessageTemplate;
+      if ( key!=null )
+      {
+         ResourceBundle resourceBundle = SeamResourceBundle.getBundle();
+         if ( resourceBundle!=null ) 
+         {
+            try
+            {
+               String bundleMessage = resourceBundle.getString(key);
+               if (bundleMessage!=null) 
+               {
+                  messageTemplate = bundleMessage;
+               }
+            }
+            catch (MissingResourceException mre) {} //swallow
+         }
+      }
+      return messageTemplate;
+   }
+   
+   @Override
+   public String toString()
+   {
+      return "[" + severity + "] " + summary + " (" + detail +")";
+   }
+   
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessages.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessages.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/StatusMessages.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,402 @@
+package org.jboss.seam.international;
+
+import static org.jboss.seam.international.StatusMessage.Severity.INFO;
+import static org.jboss.seam.international.StatusMessage.Severity.WARN;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.validator.InvalidValue;
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.international.StatusMessage.Severity;
+
+/**
+ * Abstract base class for providing status messages. View layers should provide
+ * a concrete implementation.
+ * 
+ * @author Pete Muir
+ *
+ */
+public abstract class StatusMessages implements Serializable
+{
+   private static final long serialVersionUID = -5395975397632138270L;
+   
+   public static final String COMPONENT_NAME = "org.jboss.seam.international.statusMessages";
+   
+   private List<StatusMessage> messages = new ArrayList<StatusMessage>();
+   private Map<String, List<StatusMessage>> keyedMessages = new HashMap<String, List<StatusMessage>>();
+   
+   private transient List<Runnable> tasks;
+   
+   protected List<StatusMessage> getMessages()
+   {
+      return messages;
+   }
+   
+   protected Map<String, List<StatusMessage>> getKeyedMessages()
+   {
+      return keyedMessages;
+   }
+   
+   /**
+    * Clear all status messages
+    */
+   public void clear()
+   {
+      messages.clear();
+      keyedMessages.clear();
+   }
+   
+   public void clearKeyedMessages(String id)
+   {
+      keyedMessages.remove(id);
+   }
+   
+   public void clearGlobalMessages()
+   {
+      messages.clear();
+   }
+   
+   /**
+    * 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.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    */
+   public void add(Severity severity, String key, String detailKey, String messageTemplate, String messageDetailTemplate, final Object... params)
+   {
+      final StatusMessage message = new StatusMessage(severity, key, detailKey, messageTemplate, messageDetailTemplate);
+      if (!message.isEmpty())
+      {
+         messages.add(message);
+         getTasks().add(
+               new Runnable() 
+               {
+                  
+                  public void run() 
+                  {
+                      message.interpolate(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
+    * 
+    */
+   public void addToControl(String id, Severity severity, String key, String messageTemplate, final Object... params)
+   {
+      final StatusMessage message = new StatusMessage(severity, key, null, messageTemplate, null);
+      if (!message.isEmpty())
+      {         
+         if (keyedMessages.containsKey(id))
+         {
+            keyedMessages.get(id).add(message);
+         }
+         else
+         {
+            List<StatusMessage> list = new ArrayList<StatusMessage>();
+            list.add(message);
+            keyedMessages.put(id, list);
+         }
+         getTasks().add(
+               new Runnable() 
+               {
+                  
+                  public void run() 
+                  {
+                     message.interpolate(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
+    */
+   public void add(String messageTemplate, Object... params)
+   {
+      add(INFO, messageTemplate, params);
+   }
+
+   /**
+    * Create a new status message, with the messageTemplate is as the message.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    */
+   public void add(Severity severity, String messageTemplate, Object... params)
+   {
+      add(severity, null, null, messageTemplate, null, params);
+   }
+
+   /**
+    * Create a new status message, with the messageTemplate is as the message.
+    * 
+    * 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.
+    * 
+    * A severity of INFO will be used, and you can specify parameters to be 
+    * interpolated
+    * 
+    */
+   public void addToControl(String id, String messageTemplate, Object... params)
+   {
+      addToControl(id, INFO, null, messageTemplate, params);
+   }
+
+   /**
+    * Create a new status message, with the messageTemplate is as the message.
+    * 
+    * 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
+    * 
+    */
+   public void addToControl(String id, Severity severity, String messageTemplate, Object... params)
+   {
+      addToControl(id, severity, null, messageTemplate, 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.
+    * 
+    * A severity of INFO will be used, and you can specify parameters to be 
+    * interpolated
+    */
+   public void addFromResourceBundle(String key, Object... params)
+   {
+      addFromResourceBundle(INFO, 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
+    * 
+    */
+   public void addFromResourceBundle(Severity severity, String key, Object... params)
+   {
+      addFromResourceBundleOrDefault(severity, key, 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.
+    * 
+    * A severity of INFO will be used, and you can specify parameters to be 
+    * interpolated
+    * 
+    */
+   public void addFromResourceBundleOrDefault(String key, String defaultMessageTemplate, Object... params)
+   {
+      addFromResourceBundleOrDefault(INFO, key, defaultMessageTemplate, 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.
+    * 
+    * You can also specify the severity, and parameters to be interpolated
+    * 
+    */
+   public void addFromResourceBundleOrDefault(Severity severity, String key, String defaultMessageTemplate, Object... params)
+   {
+      add(severity, key, null, defaultMessageTemplate, null, 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.
+    * 
+    * A severity of INFO will be used, and you can specify parameters to be 
+    * interpolated
+    * 
+    */
+   public void addToControlFromResourceBundle(String id, String key, Object... params)
+   {
+      addToControlFromResourceBundle(id, INFO, key, 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
+    * 
+    */
+   public void addToControlFromResourceBundle(String id, Severity severity, String key, Object... params)
+   {
+      addToControlFromResourceBundleOrDefault(id, severity, key, 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.
+    * 
+    * A severity of INFO will be used, and you can specify parameters to be 
+    * interpolated
+    * 
+    */
+   public void addToControlFromResourceBundleOrDefault(String id, String key, String defaultMessageTemplate, Object... params)
+   {
+      addToControlFromResourceBundleOrDefault(id, INFO, key, defaultMessageTemplate, 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
+    * 
+    */
+   public void addToControlFromResourceBundleOrDefault(String id, Severity severity, String key, String defaultMessageTemplate, Object... params)
+   {
+      addToControl(id, severity, key, defaultMessageTemplate, params);
+   }
+
+   /**
+    * Add an array of InvalidValues from Hibernate Validator. Each message will
+    * be added with a severity of WARN.
+    */
+   public void add(InvalidValue[] ivs)
+   {
+      for (InvalidValue iv: ivs)
+      {
+         add(iv);
+      }
+   }
+
+   /**
+    * Add an array of InvalidValues from Hibernate Validator. Each message will
+    * be added with a severity of WARN.
+    * 
+    * The name of the property that was validated will be used as the widget ID
+    */
+   public void addToControls(InvalidValue[] ivs)
+   {
+      for (InvalidValue iv: ivs)
+      {
+         addToControl(iv);
+      }
+   }
+
+   /**
+    * Add an InvalidValue from Hibernate Validator. The message will
+    * be added with a severity of WARN.
+    */
+   public void add(InvalidValue iv)
+   {
+      add( WARN, iv.getMessage() );
+   }
+
+   /**
+    * Add an InvalidValue from Hibernate Validator. The message will
+    * be added with a severity of WARN.
+    * 
+    * The name of the property that was validated will be used as the widget ID
+    */
+   public void addToControl(InvalidValue iv)
+   {
+      addToControl( iv.getPropertyName(), iv );
+   }
+
+   /**
+    * Add an InvalidValue from Hibernate Validator. The message will
+    * be added with a severity of WARN.
+    * 
+    * You can also specify the id of the widget to add the message to
+    */
+   public void addToControl(String id, InvalidValue iv)
+   {
+      addToControl( id, WARN, iv.getMessage() );
+   }
+   
+   private List<Runnable> getTasks()
+   {
+      if (tasks == null)
+      {
+         tasks = new ArrayList<Runnable>();
+      }
+      return tasks;
+   }
+   
+   protected static void runTasks()
+   {
+      if ( Contexts.isConversationContextActive() )
+      {
+         StatusMessages statusMessages = instance();
+         if (statusMessages != null)
+         {
+            statusMessages.doRunTasks();
+         }
+      }
+   }
+   
+   protected void doRunTasks()
+   {
+      if (tasks!=null)
+      {
+         for (Runnable task: tasks) task.run();
+         tasks.clear();
+      }
+   }
+   
+   public static StatusMessages instance()
+   {
+      if ( !Contexts.isConversationContextActive() )
+      {
+         throw new IllegalStateException("No active conversation context");
+      }
+      return (StatusMessages) Component.getInstance(COMPONENT_NAME, ScopeType.CONVERSATION);
+   }
+
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZone.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZone.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZone.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,36 @@
+package org.jboss.seam.international;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+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.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * Manager component for the current user's locale
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.STATELESS)
+ at Name("org.jboss.seam.international.timeZone")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, dependencies="org.jboss.seam.international.timeZoneSelector")
+public class TimeZone 
+{
+
+   @Unwrap
+   public java.util.TimeZone getTimeZone()
+   {
+      return TimeZoneSelector.instance().getTimeZone();
+   }
+   
+   public static java.util.TimeZone instance()
+   {
+      return (java.util.TimeZone) Component.getInstance(TimeZone.class, ScopeType.STATELESS);
+   }
+   
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneSelector.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneSelector.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneSelector.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,112 @@
+package org.jboss.seam.international;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import javax.faces.event.ValueChangeEvent;
+
+import org.jboss.seam.Component;
+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.contexts.Contexts;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.faces.Selector;
+
+/**
+ * Selects the current user's time zone, defaulting
+ * to the server time zone.
+ * 
+ * @author Gavin King
+ */
+ at Scope(ScopeType.SESSION)
+ at Name("org.jboss.seam.international.timeZoneSelector")
+ at BypassInterceptors
+ at Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext")
+public class TimeZoneSelector extends Selector
+{
+   private static final long serialVersionUID = -5013819375360015369L;
+   
+   private String id;
+   
+   @Create
+   public void initTimeZone()
+   {
+      String timeZoneId = getCookieValueIfEnabled();
+      if (timeZoneId!=null) setTimeZoneId(timeZoneId);
+   }
+   
+   @Override
+   protected String getCookieName()
+   {
+      return "org.jboss.seam.core.TimeZone";
+   }
+   
+   /**
+    * Force the resource bundle to reload, using the current locale, 
+    * and raise the org.jboss.seam.timeZoneSelected event
+    */
+   public void select()
+   {
+      setCookieValueIfEnabled( getTimeZoneId() );
+
+      if ( Events.exists() ) 
+      {
+          Events.instance().raiseEvent( "org.jboss.seam.timeZoneSelected", getTimeZoneId() );
+      }
+   }
+
+   public void select(ValueChangeEvent event) 
+   {
+      selectTimeZone( (String) event.getNewValue() );
+   }
+   
+   public void selectTimeZone(String timeZoneId)
+   {
+      setTimeZoneId(timeZoneId);
+      select();
+   }
+   
+   public void setTimeZone(java.util.TimeZone timeZone)
+   {
+      setTimeZoneId( timeZone.getID() );
+   }
+
+   public void setTimeZoneId(String id)
+   {
+      setDirty(this.id, id);
+      this.id = id;
+   }
+   
+   public String getTimeZoneId()
+   {
+      return id;
+   }
+
+   /**
+    * Get the selected timezone
+    */
+   public java.util.TimeZone getTimeZone() 
+   {
+      if (id==null)
+      {
+         return java.util.TimeZone.getDefault();
+      }
+      else
+      {
+         return java.util.TimeZone.getTimeZone( getTimeZoneId() );
+      }
+   }
+
+   public static TimeZoneSelector instance()
+   {
+      if ( !Contexts.isSessionContextActive() )
+      {
+         throw new IllegalStateException("No active session context");
+      }
+      return (TimeZoneSelector) Component.getInstance(TimeZoneSelector.class, ScopeType.SESSION);
+   }
+   
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneWrapper.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneWrapper.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZoneWrapper.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,102 @@
+package org.jboss.seam.international;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * A wrapper around a TimeZone that provides a more convenience interface to
+ * access the time zone information in the UI, in particular in the options of
+ * a select menu.
+ *
+ * @author Dan Allen
+ */
+public class TimeZoneWrapper extends TimeZone
+{
+   private static final int MILLISECONDS_PER_HOUR = 1000 * 60 * 60;
+
+   private TimeZone timeZone;
+
+   public TimeZoneWrapper(TimeZone tz) {
+      timeZone = tz;
+      setID(tz.getID());
+   }
+
+   @Override
+   public void setID(String id) {
+      super.setID(id);
+      timeZone = TimeZone.getTimeZone(id);
+   }
+
+   public String getId() {
+      return timeZone.getID();
+   }
+
+   public String getLabel() {
+      StringBuilder label = new StringBuilder(50);
+      label.append(getId().replace("_", " "));
+      label.append(" (UTC");
+      label.append(timeZone.getRawOffset() > 0 ? "+" : "-");
+      if (Math.abs(timeZone.getRawOffset()) < MILLISECONDS_PER_HOUR * 10) {
+         label.append("0");
+      }
+      label.append(Math.abs(timeZone.getRawOffset())/MILLISECONDS_PER_HOUR);
+      label.append(":00)");
+      return label.toString();
+   }
+
+   public TimeZone getTimeZone() {
+      return timeZone;
+   }
+
+   @Override
+   public int getOffset(int era, int year, int month, int day, int dayOfWeek, int millis) {
+      return timeZone.getOffset(era, year, month, day, dayOfWeek, millis);
+   }
+
+   @Override
+   public void setRawOffset(int offset) {
+      timeZone.setRawOffset(offset);
+   }
+
+   @Override
+   public int getRawOffset() {
+      return timeZone.getRawOffset();
+   }
+
+   @Override
+   public boolean useDaylightTime() {
+      return timeZone.useDaylightTime();
+   }
+
+   @Override
+   public boolean inDaylightTime(Date date) {
+      return timeZone.inDaylightTime(date);
+   }
+
+   @Override
+   public Object clone() {
+      return timeZone.clone();
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (obj == null) {
+         return false;
+      }
+      if (getClass() != obj.getClass()) {
+         return false;
+      }
+      final TimeZoneWrapper other = (TimeZoneWrapper) obj;
+      if (timeZone != other.timeZone && (timeZone == null || !timeZone.equals(other.timeZone))) {
+         return false;
+      }
+      return true;
+   }
+
+   @Override
+   public int hashCode() {
+      int hash = 7;
+      hash = 79 * hash + (timeZone != null ? timeZone.hashCode() : 0);
+      return hash;
+   }
+}

Added: modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZones.java
===================================================================
--- modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZones.java	                        (rev 0)
+++ modules/trunk/international/src/main/java/org/jboss/seam/international/TimeZones.java	2009-04-22 01:23:11 UTC (rev 10558)
@@ -0,0 +1,71 @@
+package org.jboss.seam.international;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TimeZone;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.Create;
+
+/**
+ * <p>Seam component that provides a list of time zones, limited to time zones
+ * with IDs in the form Continent/Place, excluding deprecated three-letter time
+ * zone IDs. The time zones returned have a fixed offset from UTC, which takes
+ * daylight savings time into account. For example, Europe/Amsterdam is UTC+1;
+ * in winter this is GMT+1 and in summer GMT+2.</p>
+ *
+ * <p>The time zone objects returned are wrapped in an implementation of
+ * TimeZone that provides a more friendly interface for accessing the time zone
+ * information. In particular, this type provides a more bean-friend property
+ * for the time zone id (id than ID) and provides a convenience property named
+ * label that formats the time zone for display in the UI. This wrapper can be
+ * disabled by setting the component property wrap to false.</p>
+ *
+ * @author Peter Hilton, Lunatech Research
+ * @author Dan Allen
+ */
+ at Scope(ScopeType.APPLICATION)
+ at Name("org.jboss.seam.international.timeZones")
+public class TimeZones
+{
+   private static final String TIMEZONE_ID_PREFIXES =
+      "^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*";
+
+   private boolean wrap = true;
+
+   private List<TimeZone> timeZones = null;
+   
+   @Create
+   public void init() {
+      timeZones = new ArrayList<TimeZone>();
+      final String[] timeZoneIds = TimeZone.getAvailableIDs();
+      for (final String id : timeZoneIds) {
+         if (id.matches(TIMEZONE_ID_PREFIXES)) {
+            timeZones.add(wrap ? new TimeZoneWrapper(TimeZone.getTimeZone(id)) : TimeZone.getTimeZone(id));
+         }
+      }
+      Collections.sort(timeZones, new Comparator<TimeZone>() {
+         public int compare(final TimeZone a, final TimeZone b) {
+            return a.getID().compareTo(b.getID());
+         }
+      });
+   }
+
+   @Unwrap
+   public List<TimeZone> getTimeZones() {
+      return timeZones;
+   }
+
+   public boolean isWrap() {
+      return wrap;
+   }
+
+   public void setWrap(boolean wrap) {
+      this.wrap = wrap;
+   }
+}




More information about the seam-commits mailing list