[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>
+ * <i18n:locale-config default-locale="en" supported-locales="en fr de"/>
+ * </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><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