Revision: 6927
Author: [email protected]
Date: Mon Nov 16 13:33:45 2009
Log: Merge trunk r6926 into this branch
Fix thread safety issues in GwtLocaleFactoryImpl and LocaleUtils.
svn merge --ignore-ancestry -c6926 \
https://google-web-toolkit.googlecode.com/svn/trunk/ .
http://code.google.com/p/google-web-toolkit/source/detail?r=6927
Added:
/releases/2.0/dev/core/src/com/google/gwt/core/ext/DefaultConfigurationProperty.java
/releases/2.0/dev/core/src/com/google/gwt/core/ext/DefaultSelectionProperty.java
Modified:
/releases/2.0/branch-info.txt
/releases/2.0/dev/core/src/com/google/gwt/core/ext/PropertyOracle.java
/releases/2.0/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
/releases/2.0/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
/releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
/releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java
/releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
/releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
=======================================
--- /dev/null
+++
/releases/2.0/dev/core/src/com/google/gwt/core/ext/DefaultConfigurationProperty.java
Mon Nov 16 13:33:45 2009
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.core.ext;
+
+import java.util.List;
+
+/**
+ * Default immutable implementation of ConfigurationProperty that receives
its
+ * values in its constructor.
+ */
+public class DefaultConfigurationProperty implements ConfigurationProperty
{
+
+ private final String name;
+ private final List<String> values;
+
+ /**
+ * Construct a configuration property.
+ *
+ * @param name the name of this property, must not be null
+ * @param values the list of possible values, must not be null and
+ * will be returned to callers, so a copy should be passed into this
+ * ctor if the caller will use this set later
+ */
+ public DefaultConfigurationProperty(String name, List<String> values) {
+ assert name != null;
+ assert values != null;
+ this.name = name;
+ this.values = values;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ DefaultConfigurationProperty other = (DefaultConfigurationProperty)
obj;
+ return name.equals(other.name)
+ && values.equals(other.values);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List<String> getValues() {
+ return values;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + name.hashCode();
+ result = prime * result + values.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ConfigProp " + name + ": " + values.toString();
+ }
+}
=======================================
--- /dev/null
+++
/releases/2.0/dev/core/src/com/google/gwt/core/ext/DefaultSelectionProperty.java
Mon Nov 16 13:33:45 2009
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
not
+ * use this file except in compliance with the License. You may obtain a
copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package com.google.gwt.core.ext;
+
+import java.util.SortedSet;
+
+/**
+ * Default immutable implementation of SelectionProperty that receives its
+ * values in its constructor.
+ */
+public class DefaultSelectionProperty implements SelectionProperty {
+
+ private final String currentValue;
+ private final String fallbackValue;
+ private final String name;
+ private final SortedSet<String> possibleValues;
+
+ /**
+ * Construct a selection property.
+ *
+ * @param currentValue current value of this property, must not be null
+ * @param fallbackValue the fallback value to use, must not be null
+ * @param name the name of this property, must not be null
+ * @param possibleValues the set of possible values, must not be null and
+ * will be returned to callers, so a copy should be passed into this
+ * ctor if the caller will use this set later
+ */
+ public DefaultSelectionProperty(String currentValue, String
fallbackValue,
+ String name, SortedSet<String> possibleValues) {
+ assert currentValue != null;
+ assert fallbackValue != null;
+ assert name != null;
+ assert possibleValues != null;
+ this.currentValue = currentValue;
+ this.fallbackValue = fallbackValue;
+ this.name = name;
+ this.possibleValues = possibleValues;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ DefaultSelectionProperty other = (DefaultSelectionProperty) obj;
+ return currentValue.equals(other.currentValue)
+ && fallbackValue.equals(other.fallbackValue)
+ && name.equals(other.name)
+ && possibleValues.equals(other.possibleValues);
+ }
+
+ public String getCurrentValue() {
+ return currentValue;
+ }
+
+ public String getFallbackValue() {
+ return fallbackValue;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public SortedSet<String> getPossibleValues() {
+ return possibleValues;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + currentValue.hashCode();
+ result = prime * result + fallbackValue.hashCode();
+ result = prime * result + name.hashCode();
+ result = prime * result + possibleValues.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "SelectionProp " + name + ": " + currentValue + " of "
+ + possibleValues.toString() + ", fallback =" + fallbackValue;
+ }
+}
=======================================
--- /releases/2.0/branch-info.txt Mon Nov 16 12:57:41 2009
+++ /releases/2.0/branch-info.txt Mon Nov 16 13:33:45 2009
@@ -692,3 +692,7 @@
Allows path to executable in RunStyleSelenium.
svn merge --ignore-ancestry -c6923
https://google-web-toolkit.googlecode.com/svn/trunk .
+tr...@6926 was merged into this branhc
+ Fix thread safety issues in GwtLocaleFactoryImpl and LocaleUtils.
+ svn merge --ignore-ancestry -c6926 \
+ https://google-web-toolkit.googlecode.com/svn/trunk/ .
=======================================
--- /releases/2.0/dev/core/src/com/google/gwt/core/ext/PropertyOracle.java
Tue May 5 13:08:14 2009
+++ /releases/2.0/dev/core/src/com/google/gwt/core/ext/PropertyOracle.java
Mon Nov 16 13:33:45 2009
@@ -25,6 +25,11 @@
* <code>BadPropertyValueException</code> if the property is undefined.
The
* result of invoking this method with the same
<code>propertyName</code> must
* be stable.
+ *
+ * @param propertyName
+ * @return the configuration property instance (never null)
+ * @throws BadPropertyValueException if the property is unknown or not a
+ * configuration property
*/
ConfigurationProperty getConfigurationProperty(String propertyName)
throws BadPropertyValueException;
@@ -38,6 +43,8 @@
* @param logger the current logger
* @param propertyName the name of the property
* @return a value for the property
+ * @throws BadPropertyValueException if the property is unknown or not
of the
+ * right type
*/
@Deprecated
String getPropertyValue(TreeLogger logger, String propertyName)
@@ -53,6 +60,8 @@
* @param logger the current logger
* @param propertyName the name of the property
* @return the possible values for the property
+ * @throws BadPropertyValueException if the property is unknown or not
of the
+ * right type
*/
@Deprecated
String[] getPropertyValueSet(TreeLogger logger, String propertyName)
@@ -63,6 +72,11 @@
* <code>BadPropertyValueException</code> if the property is either
undefined
* or has a value that is unsupported. The result of invoking this
method with
* the same <code>propertyName</code> must be stable.
+ * @param logger
+ * @param propertyName
+ * @return the selection property instance (never null)
+ * @throws BadPropertyValueException if the property is unknown or not a
+ * selection property
*/
SelectionProperty getSelectionProperty(TreeLogger logger, String
propertyName)
throws BadPropertyValueException;
=======================================
---
/releases/2.0/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
Tue Jun 16 14:20:27 2009
+++
/releases/2.0/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
Mon Nov 16 13:33:45 2009
@@ -16,12 +16,12 @@
package com.google.gwt.dev.cfg;
import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.DefaultConfigurationProperty;
+import com.google.gwt.core.ext.DefaultSelectionProperty;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
import java.io.Serializable;
-import java.util.List;
-import java.util.SortedSet;
import java.util.TreeSet;
/**
@@ -36,6 +36,13 @@
private final String[] orderedPropValues;
+ /**
+ * Create a property oracle that will return the supplied values.
+ *
+ * @param orderedProps array of binding properties
+ * @param orderedPropValues values of the above binding properties
+ * @param configProps array of config properties
+ */
public StaticPropertyOracle(BindingProperty[] orderedProps,
String[] orderedPropValues, ConfigurationProperty[] configProps) {
this.orderedProps = orderedProps;
@@ -58,24 +65,23 @@
String propertyName) throws BadPropertyValueException {
for (final ConfigurationProperty prop : configProps) {
if (prop.getName().equals(propertyName)) {
- return new com.google.gwt.core.ext.ConfigurationProperty() {
- public String getName() {
- return prop.getName();
- }
-
- public List<String> getValues() {
- return prop.getValues();
- }
- };
+ return new DefaultConfigurationProperty(prop.getName(),
+ prop.getValues());
}
}
throw new BadPropertyValueException(propertyName);
}
+ /**
+ * @return an array of binding properties.
+ */
public BindingProperty[] getOrderedProps() {
return orderedProps;
}
+ /**
+ * @return an array of binding property values.
+ */
public String[] getOrderedPropValues() {
return orderedPropValues;
}
@@ -138,7 +144,6 @@
for (int i = 0; i < orderedProps.length; i++) {
final BindingProperty prop = orderedProps[i];
final String name = prop.getName();
- final String fallback = prop.getFallback();
if (name.equals(propertyName)) {
final String value = orderedPropValues[i];
String[] values = prop.getDefinedValues();
@@ -146,24 +151,8 @@
for (String v : values) {
possibleValues.add(v);
}
-
- return new com.google.gwt.core.ext.SelectionProperty() {
- public String getCurrentValue() {
- return value;
- }
-
- public String getFallbackValue() {
- return fallback;
- }
-
- public String getName() {
- return name;
- }
-
- public SortedSet<String> getPossibleValues() {
- return possibleValues;
- }
- };
+ return new DefaultSelectionProperty(value, prop.getFallback(),
name,
+ possibleValues);
}
}
=======================================
---
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
Fri Oct 16 20:54:44 2009
+++
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpaceOOPHM.java
Mon Nov 16 13:33:45 2009
@@ -100,7 +100,7 @@
@Override
protected JsValue doInvoke(String name, Object jthis, Class<?>[] types,
Object[] args) throws Throwable {
- TreeLogger branch = host.getLogger().branch(TreeLogger.DEBUG,
+ TreeLogger branch = host.getLogger().branch(TreeLogger.SPAM,
"Invoke native method " + name, null);
CompilingClassLoader isolatedClassLoader = getIsolatedClassLoader();
JsValueOOPHM jsthis = new JsValueOOPHM();
@@ -121,7 +121,7 @@
returnVal);
branch.log(TreeLogger.SPAM, " returned " + returnVal);
} catch (Throwable t) {
- branch.log(TreeLogger.DEBUG, "exception thrown", t);
+ branch.log(TreeLogger.SPAM, "exception thrown", t);
throw t;
}
return returnVal;
=======================================
---
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
Mon Aug 17 09:47:12 2009
+++
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ModuleSpacePropertyOracle.java
Mon Nov 16 13:33:45 2009
@@ -16,6 +16,8 @@
package com.google.gwt.dev.shell;
import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.DefaultConfigurationProperty;
+import com.google.gwt.core.ext.DefaultSelectionProperty;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.SelectionProperty;
import com.google.gwt.core.ext.TreeLogger;
@@ -45,6 +47,12 @@
private final ModuleSpace space;
+ /**
+ * Create a property oracle that computes its properties from a module.
+ *
+ * @param props
+ * @param space
+ */
public ModuleSpacePropertyOracle(Properties props, ModuleSpace space) {
this.space = space;
this.props = props;
@@ -57,15 +65,7 @@
final ConfigurationProperty cprop = (ConfigurationProperty) prop;
final String name = cprop.getName();
final List<String> values = cprop.getValues();
- return new com.google.gwt.core.ext.ConfigurationProperty() {
- public String getName() {
- return name;
- }
-
- public List<String> getValues() {
- return values;
- }
- };
+ return new DefaultConfigurationProperty(name, values);
} else {
throw new BadPropertyValueException(propertyName);
}
@@ -132,24 +132,8 @@
for (String v : cprop.getDefinedValues()) {
possibleValues.add(v);
}
- return new com.google.gwt.core.ext.SelectionProperty() {
-
- public String getCurrentValue() {
- return value;
- }
-
- public String getFallbackValue() {
- return fallback;
- }
-
- public String getName() {
- return name;
- }
-
- public SortedSet<String> getPossibleValues() {
- return possibleValues;
- }
- };
+ return new DefaultSelectionProperty(value, fallback, name,
+ possibleValues);
} else {
throw new BadPropertyValueException(propertyName);
}
=======================================
---
/releases/2.0/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
Tue Jun 23 20:13:51 2009
+++
/releases/2.0/user/src/com/google/gwt/i18n/rebind/CurrencyListGenerator.java
Mon Nov 16 13:33:45 2009
@@ -258,9 +258,9 @@
TypeOracle typeOracle = context.getTypeOracle();
PropertyOracle propertyOracle = context.getPropertyOracle();
- LocaleUtils.init(logger, propertyOracle);
- GwtLocale locale = LocaleUtils.getCompileLocale();
- Set<GwtLocale> runtimeLocales = LocaleUtils.getRuntimeLocales();
+ LocaleUtils localeUtils = LocaleUtils.getInstance(logger,
propertyOracle);
+ GwtLocale locale = localeUtils.getCompileLocale();
+ Set<GwtLocale> runtimeLocales = localeUtils.getRuntimeLocales();
JClassType targetClass;
try {
=======================================
---
/releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
Mon May 18 11:47:32 2009
+++
/releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleInfoGenerator.java
Mon Nov 16 13:33:45 2009
@@ -81,7 +81,8 @@
TypeOracle typeOracle = context.getTypeOracle();
// Get the current locale and interface type.
PropertyOracle propertyOracle = context.getPropertyOracle();
- LocaleUtils.init(logger, propertyOracle);
+ LocaleUtils localeUtils = LocaleUtils.getInstance(logger,
+ propertyOracle);
JClassType targetClass;
try {
@@ -90,12 +91,14 @@
logger.log(TreeLogger.ERROR, "No such type " + typeName, e);
throw new UnableToCompleteException();
}
- assert
(LocaleInfoImpl.class.getName().equals(targetClass.getQualifiedSourceName()));
+ assert (LocaleInfoImpl.class.getName().equals(
+ targetClass.getQualifiedSourceName()));
String packageName = targetClass.getPackage().getName();
String superClassName = targetClass.getName().replace('.', '_')
+ "_shared";
- Set<GwtLocale> localeSet = LocaleUtils.getAllLocales();
- GwtLocaleImpl[] allLocales = localeSet.toArray(new
GwtLocaleImpl[localeSet.size()]);
+ Set<GwtLocale> localeSet = localeUtils.getAllLocales();
+ GwtLocaleImpl[] allLocales = localeSet.toArray(
+ new GwtLocaleImpl[localeSet.size()]);
// sort for deterministic output
Arrays.sort(allLocales);
PrintWriter pw = context.tryCreate(logger, packageName,
superClassName);
@@ -184,10 +187,10 @@
writer.println("}-*/;");
writer.commit(logger);
}
- GwtLocale locale = LocaleUtils.getCompileLocale();
+ GwtLocale locale = localeUtils.getCompileLocale();
String className = targetClass.getName().replace('.', '_') + "_"
+ locale.getAsString();
- Set<GwtLocale> runtimeLocales = LocaleUtils.getRuntimeLocales();
+ Set<GwtLocale> runtimeLocales = localeUtils.getRuntimeLocales();
if (!runtimeLocales.isEmpty()) {
className += "_runtimeSelection";
}
@@ -219,7 +222,6 @@
writer.println("public DateTimeConstants getDateTimeConstants() {");
LocalizableGenerator localizableGenerator = new
LocalizableGenerator();
// Avoid warnings for trying to create the same type multiple times
- @SuppressWarnings("hiding")
GeneratorContext subContext = new CachedGeneratorContext(context);
generateConstantsLookup(logger, subContext, writer,
localizableGenerator,
runtimeLocales, locale,
=======================================
--- /releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java Thu
Nov 12 12:19:29 2009
+++ /releases/2.0/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java Mon
Nov 16 13:33:45 2009
@@ -25,8 +25,10 @@
import com.google.gwt.i18n.shared.GwtLocaleFactory;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
@@ -34,10 +36,58 @@
* Utility methods for dealing with locales.
*/
public class LocaleUtils {
- // TODO(jat): rewrite to avoid statics
+
+ /**
+ * A key for lookup of computed values in a cache.
+ */
+ private static class CacheKey {
+ private final SelectionProperty localeProperty;
+ private final ConfigurationProperty runtimeLocaleProperty;
+
+ /**
+ * Create a key for cache lookup.
+ *
+ * @param localeProperty "locale" property, must not be null
+ * @param runtimeLocaleProperty "runtime.locales" property, must not
be null
+ */
+ public CacheKey(SelectionProperty localeProperty,
+ ConfigurationProperty runtimeLocaleProperty) {
+ this.localeProperty = localeProperty;
+ this.runtimeLocaleProperty = runtimeLocaleProperty;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ CacheKey other = (CacheKey) obj;
+ return localeProperty.equals(other.localeProperty)
+ && runtimeLocaleProperty.equals(other.runtimeLocaleProperty);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + localeProperty.hashCode();
+ result = prime * result + runtimeLocaleProperty.hashCode();
+ return result;
+ }
+ }
private static final GwtLocaleFactoryImpl factory = new
GwtLocaleFactoryImpl();
+ private static final Object cacheLock = new Object[0];
+
+ private static Map<CacheKey, LocaleUtils> cache;
+
/**
* The token representing the locale property controlling Localization.
*/
@@ -48,20 +98,123 @@
*/
private static final String PROP_RUNTIME_LOCALES = "runtime.locales";
- private static GwtLocale compileLocale;
-
- private static final Set<GwtLocale> allLocales = new
HashSet<GwtLocale>();
-
- private static final Set<GwtLocale> allCompileLocales = new
HashSet<GwtLocale>();
-
- private static final Set<GwtLocale> runtimeLocales = new
HashSet<GwtLocale>();
-
- public static synchronized void clear() {
- allCompileLocales.clear();
- allLocales.clear();
- compileLocale = null;
- factory.clear();
- runtimeLocales.clear();
+ /**
+ * Clear any static state associated with LocaleUtils.
+ */
+ public static synchronized void clear() {
+ factory.clear();
+ synchronized (cacheLock) {
+ cache = null;
+ }
+ }
+
+ /**
+ * Create a new LocaleUtils instance for the given PropertyOracle.
Returned
+ * instances will be immutable and can be shared across threads.
+ *
+ * @param logger
+ * @param propertyOracle
+ * @return LocaleUtils instance
+ */
+ public static LocaleUtils getInstance(TreeLogger logger,
+ PropertyOracle propertyOracle) {
+ try {
+ SelectionProperty localeProp
+ = propertyOracle.getSelectionProperty(logger, PROP_LOCALE);
+ ConfigurationProperty runtimeLocaleProp
+ = propertyOracle.getConfigurationProperty(PROP_RUNTIME_LOCALES);
+ CacheKey key = new CacheKey(localeProp, runtimeLocaleProp);
+ synchronized (cacheLock) {
+ if (cache == null) {
+ cache = new HashMap<CacheKey, LocaleUtils>();
+ }
+ LocaleUtils localeUtils = cache.get(key);
+ if (localeUtils == null) {
+ localeUtils = createInstance(logger, localeProp,
runtimeLocaleProp);
+ cache.put(key, localeUtils);
+ }
+ return localeUtils;
+ }
+ } catch (BadPropertyValueException e) {
+ // if we don't have locale properties defined, just return a basic
one
+ logger.log(TreeLogger.WARN,
+ "Unable to get locale properties, using defaults", e);
+ GwtLocale defaultLocale = factory.fromString("default");
+ Set<GwtLocale> allLocales = new HashSet<GwtLocale>();
+ allLocales.add(defaultLocale);
+ return new LocaleUtils(defaultLocale, allLocales, allLocales,
+ Collections.<GwtLocale>emptySet());
+ }
+ }
+
+ /**
+ * Get a shared GwtLocale factory so instances are cached between all
uses.
+ *
+ * @return singleton GwtLocaleFactory instance.
+ */
+ public static synchronized GwtLocaleFactory getLocaleFactory() {
+ return factory;
+ }
+
+ private static LocaleUtils createInstance(TreeLogger logger,
+ SelectionProperty localeProp, ConfigurationProperty prop) {
+ GwtLocale compileLocale = null;
+ Set<GwtLocale> allLocales = new HashSet<GwtLocale>();
+ Set<GwtLocale> allCompileLocales = new HashSet<GwtLocale>();
+ Set<GwtLocale> runtimeLocales = new HashSet<GwtLocale>();
+ String localeName = localeProp.getCurrentValue();
+ SortedSet<String> localeValues = localeProp.getPossibleValues();
+
+ GwtLocaleFactory factoryInstance = getLocaleFactory();
+ GwtLocale newCompileLocale = factoryInstance.fromString(localeName);
+ compileLocale = newCompileLocale;
+ for (String localeValue : localeValues) {
+ allCompileLocales.add(factoryInstance.fromString(localeValue));
+ }
+ allLocales.addAll(allCompileLocales);
+
+ List<String> rtLocaleNames = prop.getValues();
+ if (rtLocaleNames != null) {
+ for (String rtLocale : rtLocaleNames) {
+ GwtLocale locale = factoryInstance.fromString(rtLocale);
+ // TODO(jat): remove use of labels
+ existingLocales:
+ for (GwtLocale existing : allCompileLocales) {
+ for (GwtLocale alias : existing.getAliases()) {
+ if (!alias.isDefault() && locale.inheritsFrom(alias)
+ && locale.usesSameScript(alias)) {
+ allLocales.add(locale);
+ break existingLocales;
+ }
+ }
+ }
+ if (!compileLocale.isDefault()
+ && locale.inheritsFrom(compileLocale)
+ && locale.usesSameScript(compileLocale)) {
+ // TODO(jat): don't include runtime locales which also inherit
+ // from a more-specific compile locale than this one
+ runtimeLocales.add(locale);
+ }
+ }
+ }
+ return new LocaleUtils(compileLocale, allLocales, allCompileLocales,
+ runtimeLocales);
+ }
+
+ private final Set<GwtLocale> allCompileLocales;
+
+ private final Set<GwtLocale> allLocales;
+
+ private final GwtLocale compileLocale;
+
+ private final Set<GwtLocale> runtimeLocales;
+
+ private LocaleUtils(GwtLocale compileLocale, Set<GwtLocale> allLocales,
+ Set<GwtLocale> allCompileLocales, Set<GwtLocale> runtimeLocales) {
+ this.compileLocale = compileLocale;
+ this.allLocales = Collections.unmodifiableSet(allLocales);
+ this.allCompileLocales =
Collections.unmodifiableSet(allCompileLocales);
+ this.runtimeLocales = Collections.unmodifiableSet(runtimeLocales);
}
/**
@@ -69,8 +222,8 @@
*
* @return unmodifiable set of all compile-time locales
*/
- public static synchronized Set<GwtLocale> getAllCompileLocales() {
- return Collections.unmodifiableSet(allCompileLocales);
+ public Set<GwtLocale> getAllCompileLocales() {
+ return allCompileLocales;
}
/**
@@ -79,25 +232,16 @@
*
* @return unmodifiable set of all locales
*/
- public static synchronized Set<GwtLocale> getAllLocales() {
- return Collections.unmodifiableSet(allLocales);
+ public Set<GwtLocale> getAllLocales() {
+ return allLocales;
}
/**
* @return the static compile-time locale for this permutation.
*/
- public static synchronized GwtLocale getCompileLocale() {
+ public GwtLocale getCompileLocale() {
return compileLocale;
}
-
- /**
- * Get a shared GwtLocale factory so instances are cached between all
uses.
- *
- * @return singleton GwtLocaleFactory instance.
- */
- public static synchronized GwtLocaleFactory getLocaleFactory() {
- return factory;
- }
/**
* Returns a list of locales which are children of the current
compile-time
@@ -105,69 +249,7 @@
*
* @return unmodifiable list of matching locales
*/
- public static synchronized Set<GwtLocale> getRuntimeLocales() {
- return Collections.unmodifiableSet(runtimeLocales);
- }
-
- /**
- * Initialize from properties. Only needs to be called once, before any
other
- * calls.
- *
- * @param logger
- * @param propertyOracle
- */
- public static synchronized void init(TreeLogger logger, PropertyOracle
propertyOracle) {
- try {
- SelectionProperty localeProp
- = propertyOracle.getSelectionProperty(logger, PROP_LOCALE);
- String localeName = localeProp.getCurrentValue();
- SortedSet<String> localeValues = localeProp.getPossibleValues();
-
- GwtLocale newCompileLocale = factory.fromString(localeName);
- if (newCompileLocale.equals(compileLocale)) {
- return;
- }
- compileLocale = newCompileLocale;
- allLocales.clear();
- allCompileLocales.clear();
- runtimeLocales.clear();
- for (String localeValue : localeValues) {
- allCompileLocales.add(factory.fromString(localeValue));
- }
- allLocales.addAll(allCompileLocales);
-
- ConfigurationProperty prop
- = propertyOracle.getConfigurationProperty(PROP_RUNTIME_LOCALES);
- List<String> rtLocaleNames = prop.getValues();
- if (rtLocaleNames != null) {
- for (String rtLocale : rtLocaleNames) {
- GwtLocale locale = factory.fromString(rtLocale);
- // TODO(jat): remove use of labels
- existingLocales:
- for (GwtLocale existing : allCompileLocales) {
- for (GwtLocale alias : existing.getAliases()) {
- if (!alias.isDefault() && locale.inheritsFrom(alias)
- && locale.usesSameScript(alias)) {
- allLocales.add(locale);
- break existingLocales;
- }
- }
- }
- if (!compileLocale.isDefault()
- && locale.inheritsFrom(compileLocale)
- && locale.usesSameScript(compileLocale)) {
- // TODO(jat): don't include runtime locales which also inherit
- // from a more-specific compile locale than this one
- runtimeLocales.add(locale);
- }
- }
- }
- } catch (BadPropertyValueException e) {
- logger.log(TreeLogger.TRACE,
- "Unable to get locale properties, using defaults", e);
- compileLocale = factory.fromString("default");
- allLocales.add(compileLocale);
- return;
- }
+ public Set<GwtLocale> getRuntimeLocales() {
+ return runtimeLocales;
}
}
=======================================
---
/releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
Mon Nov 2 12:44:54 2009
+++
/releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleFactoryImpl.java
Mon Nov 16 13:33:45 2009
@@ -24,31 +24,38 @@
import java.util.Map;
/**
- * Creates server-side GwtLocale instances.
+ * Creates server-side GwtLocale instances. Thread-safe.
*/
public class GwtLocaleFactoryImpl implements GwtLocaleFactory {
- // TODO(jat): remove code duplication here by combining these
private static boolean isAlpha(String str, int min, int max) {
- int len = str.length();
- if (len < min || len > max) {
- return false;
- }
- for (int i = 0; i < len; ++i) {
- if (!Character.isLetter(str.charAt(i))) {
- return false;
- }
- }
- return true;
+ return matches(str, min, max, true);
}
private static boolean isDigit(String str, int min, int max) {
+ return matches(str, min, max, false);
+ }
+
+ /**
+ * Check if the supplied string matches length and composition
requirements.
+ *
+ * @param str string to check
+ * @param min minimum length
+ * @param max maximum length
+ * @param lettersNotDigits true if all characters should be letters,
false if
+ * all characters should be digits
+ * @return true if the string is of a proper length and contains only the
+ * specified characters
+ */
+ private static boolean matches(String str, int min, int max,
+ boolean lettersNotDigits) {
int len = str.length();
if (len < min || len > max) {
return false;
}
for (int i = 0; i < len; ++i) {
- if (!Character.isDigit(str.charAt(i))) {
+ if ((lettersNotDigits && !Character.isLetter(str.charAt(i)))
+ || (!lettersNotDigits && !Character.isDigit(str.charAt(i)))) {
return false;
}
}
@@ -63,13 +70,24 @@
str.substring(1).toLowerCase(Locale.ENGLISH);
}
+ private final Object instanceCacheLock = new Object[0];
+
// Locales are stored pointing at themselves. A new instance is created,
// which is pretty cheap, then looked up here. If it exists, the old
// one is used instead to preserved cached data structures.
- private Map<GwtLocaleImpl, GwtLocaleImpl> instanceCache = new
HashMap<GwtLocaleImpl, GwtLocaleImpl>();
-
+ private Map<GwtLocaleImpl, GwtLocaleImpl> instanceCache
+ = new HashMap<GwtLocaleImpl, GwtLocaleImpl>();
+
+ /**
+ * Clear an embedded cache of instances when they are no longer needed.
+ * <p>
+ * Note that GwtLocale instances constructed after this is called will
not
+ * maintain identity with instances constructed before this call.
+ */
public void clear() {
- instanceCache.clear();
+ synchronized (instanceCacheLock) {
+ instanceCache.clear();
+ }
}
public GwtLocale fromComponents(String language, String script,
@@ -100,10 +118,12 @@
}
GwtLocaleImpl locale = new GwtLocaleImpl(this, language, region,
script,
variant);
- if (instanceCache.containsKey(locale)) {
- return instanceCache.get(locale);
- }
- instanceCache.put(locale, locale);
+ synchronized (instanceCacheLock) {
+ if (instanceCache.containsKey(locale)) {
+ return instanceCache.get(locale);
+ }
+ instanceCache.put(locale, locale);
+ }
return locale;
}
@@ -185,5 +205,4 @@
public GwtLocale getDefault() {
return fromComponents(null, null, null, null);
}
-
-}
+}
=======================================
--- /releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
Mon Nov 2 12:44:54 2009
+++ /releases/2.0/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
Mon Nov 16 13:33:45 2009
@@ -40,9 +40,9 @@
* Maps deprecated language codes to the canonical code. Strings are
always
* in pairs, with the first being the canonical code and the second being
* a deprecated code which maps to it.
- *
+ * <p>
* Source: http://www.loc.gov/standards/iso639-2/php/code_changes.php
- *
+ * <p>
* TODO: consider building maps if this list grows much.
*/
private static final String[] deprecatedLanguages = new String[] {
@@ -62,9 +62,9 @@
* cannot be done automatically (such as cs -> rs/me) -- perhaps we could
* have a way of flagging region codes which are no longer valid and
allow
* an appropriate warning message.
- *
+ * <p>
* Source: http://en.wikipedia.org/wiki/ISO_3166-1
- *
+ * <p>
* TODO: consider building maps if this list grows much.
*/
private static final String[] deprecatedRegions = new String[] {
@@ -233,9 +233,13 @@
private final String variant;
- private ArrayList<GwtLocale> cachedSearchList;
-
- private ArrayList<GwtLocale> cachedAliases;
+ private final Object cacheLock = new Object[0];
+
+ // protected by cacheLock
+ private List<GwtLocale> cachedSearchList;
+
+ // protected by cacheLock
+ private List<GwtLocale> cachedAliases;
/**
* Must only be called from a factory to preserve instance caching.
@@ -280,40 +284,44 @@
public List<GwtLocale> getAliases() {
// TODO(jat): more locale aliases? better way to encode them?
- if (cachedAliases == null) {
- cachedAliases = new ArrayList<GwtLocale>();
- GwtLocale canonicalForm = getCanonicalForm();
- Set<GwtLocale> seen = new HashSet<GwtLocale>();
- cachedAliases.add(canonicalForm);
- ArrayList<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
- nextGroup.add(this);
- // Account for default script
- String defaultScript =
DefaultLanguageScripts.getDefaultScript(language);
- if (defaultScript != null) {
- if (script == null) {
- nextGroup.add(factory.fromComponents(language, defaultScript,
region,
- variant));
- } else if (script.equals(defaultScript)) {
- nextGroup.add(factory.fromComponents(language, null, region,
variant));
- }
- }
- while (!nextGroup.isEmpty()) {
- List<GwtLocale> thisGroup = nextGroup;
- nextGroup = new ArrayList<GwtLocale>();
- for (GwtLocale locale : thisGroup) {
- if (seen.contains(locale)) {
- continue;
- }
- seen.add(locale);
- if (!locale.equals(canonicalForm)) {
- cachedAliases.add(locale);
- }
- addDeprecatedPairs(factory, locale, nextGroup);
- addSpecialAliases(factory, locale, nextGroup);
- }
- }
- }
- return Collections.unmodifiableList(cachedAliases);
+ synchronized (cacheLock) {
+ if (cachedAliases == null) {
+ cachedAliases = new ArrayList<GwtLocale>();
+ GwtLocale canonicalForm = getCanonicalForm();
+ Set<GwtLocale> seen = new HashSet<GwtLocale>();
+ cachedAliases.add(canonicalForm);
+ ArrayList<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
+ nextGroup.add(this);
+ // Account for default script
+ String defaultScript =
DefaultLanguageScripts.getDefaultScript(language);
+ if (defaultScript != null) {
+ if (script == null) {
+ nextGroup.add(factory.fromComponents(language, defaultScript,
+ region, variant));
+ } else if (script.equals(defaultScript)) {
+ nextGroup.add(factory.fromComponents(language, null, region,
+ variant));
+ }
+ }
+ while (!nextGroup.isEmpty()) {
+ List<GwtLocale> thisGroup = nextGroup;
+ nextGroup = new ArrayList<GwtLocale>();
+ for (GwtLocale locale : thisGroup) {
+ if (seen.contains(locale)) {
+ continue;
+ }
+ seen.add(locale);
+ if (!locale.equals(canonicalForm)) {
+ cachedAliases.add(locale);
+ }
+ addDeprecatedPairs(factory, locale, nextGroup);
+ addSpecialAliases(factory, locale, nextGroup);
+ }
+ }
+ cachedAliases = Collections.unmodifiableList(cachedAliases);
+ }
+ return cachedAliases;
+ }
}
public String getAsString() {
@@ -408,42 +416,45 @@
public List<GwtLocale> getCompleteSearchList() {
// TODO(jat): get zh_Hant to come before zh in search list for zh_TW
- if (cachedSearchList == null) {
- cachedSearchList = new ArrayList<GwtLocale>();
- Set<GwtLocale> seen = new HashSet<GwtLocale>();
- List<GwtLocale> thisGroup = new
ArrayList<GwtLocale>(this.getAliases());
- seen.addAll(thisGroup);
- GwtLocale defLocale = factory.getDefault();
- seen.add(defLocale);
- while (!thisGroup.isEmpty()) {
- cachedSearchList.addAll(thisGroup);
- List<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
- for (GwtLocale locale : thisGroup) {
- List<GwtLocale> work = new
ArrayList<GwtLocale>(locale.getAliases());
- work.removeAll(seen);
- nextGroup.addAll(work);
- seen.addAll(work);
- work.clear();
- if (locale.getRegion() != null) {
- addImmediateParentRegions(factory, locale, work);
- } else if (locale.getVariant() != null) {
- work.add(factory.fromComponents(locale.getLanguage(),
- locale.getScript(), null, null));
- } else if (locale.getScript() != null) {
- work.add(factory.fromComponents(locale.getLanguage(), null,
null,
- null));
- }
- work.removeAll(seen);
- nextGroup.addAll(work);
- seen.addAll(work);
- }
- thisGroup = nextGroup;
- }
- if (!isDefault()) {
- cachedSearchList.add(defLocale);
- }
- }
- return cachedSearchList;
+ synchronized (cacheLock) {
+ if (cachedSearchList == null) {
+ cachedSearchList = new ArrayList<GwtLocale>();
+ Set<GwtLocale> seen = new HashSet<GwtLocale>();
+ List<GwtLocale> thisGroup = new
ArrayList<GwtLocale>(this.getAliases());
+ seen.addAll(thisGroup);
+ GwtLocale defLocale = factory.getDefault();
+ seen.add(defLocale);
+ while (!thisGroup.isEmpty()) {
+ cachedSearchList.addAll(thisGroup);
+ List<GwtLocale> nextGroup = new ArrayList<GwtLocale>();
+ for (GwtLocale locale : thisGroup) {
+ List<GwtLocale> work = new
ArrayList<GwtLocale>(locale.getAliases());
+ work.removeAll(seen);
+ nextGroup.addAll(work);
+ seen.addAll(work);
+ work.clear();
+ if (locale.getRegion() != null) {
+ addImmediateParentRegions(factory, locale, work);
+ } else if (locale.getVariant() != null) {
+ work.add(factory.fromComponents(locale.getLanguage(),
+ locale.getScript(), null, null));
+ } else if (locale.getScript() != null) {
+ work.add(factory.fromComponents(locale.getLanguage(), null,
null,
+ null));
+ }
+ work.removeAll(seen);
+ nextGroup.addAll(work);
+ seen.addAll(work);
+ }
+ thisGroup = nextGroup;
+ }
+ if (!isDefault()) {
+ cachedSearchList.add(defLocale);
+ }
+ cachedSearchList = Collections.unmodifiableList(cachedSearchList);
+ }
+ return cachedSearchList;
+ }
}
/**
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors