You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/04/29 18:11:12 UTC
svn commit: r939358 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/services/
main/java/org/apache/tapestry5/services/
test/java/org/apache/tapestry5/internal/services/
Author: hlship
Date: Thu Apr 29 16:11:11 2010
New Revision: 939358
URL: http://svn.apache.org/viewvc?rev=939358&view=rev
Log:
TAP5-1120: It is not possible to override the default Translator contributions to the TranslatorSource service
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java?rev=939358&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java Thu Apr 29 16:11:11 2010
@@ -0,0 +1,45 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.internal.services;
+
+import java.util.Map;
+
+import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.services.TranslatorAlternatesSource;
+
+@SuppressWarnings("unchecked")
+public class TranslatorAlternatesSourceImpl implements TranslatorAlternatesSource
+{
+ private final Map<String, Translator> configuration;
+
+ public TranslatorAlternatesSourceImpl(Map<String, Translator> configuration)
+ {
+ this.configuration = configuration;
+
+ for (Map.Entry<String, Translator> me : configuration.entrySet())
+ {
+ if (!me.getKey().equalsIgnoreCase(me.getValue().getName()))
+ throw new RuntimeException(String.format(
+ "Contribution key '%s' does not match '%s' (the name of the corresponding Translator).", me
+ .getKey(), me.getValue().getName()));
+ }
+ }
+
+ public Map<String, Translator> getTranslatorAlternates()
+ {
+ return configuration;
+ }
+
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java?rev=939358&r1=939357&r2=939358&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TranslatorSourceImpl.java Thu Apr 29 16:11:11 2010
@@ -14,6 +14,7 @@
package org.apache.tapestry5.internal.services;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -25,14 +26,22 @@ import org.apache.tapestry5.ioc.util.Unk
import org.apache.tapestry5.services.InvalidationListener;
import org.apache.tapestry5.services.TranslatorSource;
+@SuppressWarnings("unchecked")
public class TranslatorSourceImpl implements TranslatorSource, InvalidationListener
{
- private final Map<String, Translator> translators = CollectionFactory.newCaseInsensitiveMap();
+ private final Map<String, Translator> nameToTranslator = CollectionFactory.newCaseInsensitiveMap();
private final StrategyRegistry<Translator> registry;
+ private static final Map<String, Translator> EMPTY = Collections.emptyMap();
+
public TranslatorSourceImpl(Map<Class, Translator> configuration)
{
+ this(configuration, EMPTY);
+ }
+
+ public TranslatorSourceImpl(Map<Class, Translator> configuration, Map<String, Translator> alternates)
+ {
for (Map.Entry<Class, Translator> me : configuration.entrySet())
{
Class type = me.getKey();
@@ -45,7 +54,28 @@ public class TranslatorSourceImpl implem
"Contributed translator for type %s reports its type as %s. Please change the contribution so that the key matches that translator type.",
type.getName(), translator.getType().getName()));
- translators.put(translator.getName(), translator);
+ String name = translator.getName();
+
+ if (nameToTranslator.containsKey(name))
+ throw new RuntimeException(
+ String
+ .format(
+ "Two different Translators contributed to the TranslatorSource service use the same translator name: '%s'. Translator names must be unique.",
+ name));
+
+ nameToTranslator.put(name, translator);
+ }
+
+ for (String name : alternates.keySet())
+ {
+ if (nameToTranslator.containsKey(name))
+ throw new RuntimeException(
+ String
+ .format(
+ "Translator '%s' contributed to the TranslatorAlternatesSource service has the same name as a standard Translator contributed to the TranslatorSource service.",
+ name));
+
+ nameToTranslator.put(name, alternates.get(name));
}
registry = StrategyRegistry.newInstance(Translator.class, configuration, true);
@@ -53,12 +83,11 @@ public class TranslatorSourceImpl implem
public Translator get(String name)
{
-
- Translator result = translators.get(name);
+ Translator result = nameToTranslator.get(name);
if (result == null)
throw new UnknownValueException(String.format("Unknown translator type '%s'.", name), new AvailableValues(
- "translators", translators));
+ "translators", nameToTranslator));
return result;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=939358&r1=939357&r2=939358&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Thu Apr 29 16:11:11 2010
@@ -371,6 +371,7 @@ public final class TapestryModule
binder.bind(Dispatcher.class, AssetDispatcher.class).withId("AssetDispatcher");
binder.bind(AssetPathConstructor.class, AssetPathConstructorImpl.class);
binder.bind(JavascriptStackSource.class, JavascriptStackSourceImpl.class);
+ binder.bind(TranslatorAlternatesSource.class, TranslatorAlternatesSourceImpl.class);
}
// ========================================================================
@@ -1530,10 +1531,13 @@ public final class TapestryModule
return service;
}
- public static TranslatorSource buildTranslatorSource(@Autobuild
- TranslatorSourceImpl service, @ComponentClasses
- InvalidationEventHub hub)
+ public static TranslatorSource buildTranslatorSource(Map<Class, Translator> configuration,
+ TranslatorAlternatesSource alternatesSource, @ComponentClasses
+ InvalidationEventHub hub)
{
+ TranslatorSourceImpl service = new TranslatorSourceImpl(configuration, alternatesSource
+ .getTranslatorAlternates());
+
hub.addInvalidationListener(service);
return service;
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java?rev=939358&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java Thu Apr 29 16:11:11 2010
@@ -0,0 +1,40 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.services;
+
+import java.util.Map;
+
+import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
+
+/**
+ * This service is used by {@link TranslatorSource} to specify {@link Translator} <em>alternates</em>: translators that
+ * are used when specified explicitly by name. These translators may overlap the standard translators
+ * by type (thus requiring a separate configuration).
+ * <p>
+ * Translators contributed to this configuration must have names that do not overlap the standard translators. Further,
+ * the contribution key must match the {@linkplain Translator#getName() translator name}.
+ *
+ * @since 5.2.0
+ */
+@UsesMappedConfiguration(Translator.class)
+public interface TranslatorAlternatesSource
+{
+ /**
+ * Get the mapping from name to Translator, based on the contributions to the service. It will be verified
+ * that the keys of the map corresponding to the names of the Translator values.
+ */
+ Map<String, Translator> getTranslatorAlternates();
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorAlternatesSource.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java?rev=939358&r1=939357&r2=939358&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TranslatorSource.java Thu Apr 29 16:11:11 2010
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -16,41 +16,57 @@ package org.apache.tapestry5.services;
import org.apache.tapestry5.Translator;
import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
+import org.apache.tapestry5.ioc.util.StrategyRegistry;
/**
- * A source for {@link org.apache.tapestry5.Translator}s, either by name or by property type.
+ * A source for {@link org.apache.tapestry5.Translator}s, either by name or by property type. The source knows
+ * about two sets of translators: the <em>standard</em> translators contributed directly to the service
+ * and the <em>alternate</em> translators, contributed to the {@link TranslatorAlternatesSource} service.
* <p/>
- * The configuration includes all the translators; each contributed translator must have a unique {@linkplain
- * org.apache.tapestry5.Translator#getName() name}.
+ * Each contributed translator must have a unique {@linkplain org.apache.tapestry5.Translator#getName() name}.
+ * <p>
+ * Generally, Translators are matched by type (i.e., the type matching a particular property that will be read or
+ * updated). Contributions to this service use a {@link StrategyRegistry} to match by type. Translators can also be
+ * selected by name. The {@link TranslatorAlternatesSource} service configuration is often used for this purpose.
+ * <p>
+ * The contribution key must match the {@linkplain Translator#getType() translator type}.
*/
@UsesConfiguration(Translator.class)
+@SuppressWarnings("unchecked")
public interface TranslatorSource
{
/**
- * Returns the translator with the given logical name.
- *
- * @param name name of translator (as configured)
+ * Returns the translator with the given name (either a standard translator, or an alternate).
+ *
+ * @param name
+ * name of translator (as configured, but case is ignored)
* @return the shared translator instance
- * @throws RuntimeException if no translator is configured for the provided name
+ * @throws RuntimeException
+ * if no translator is configured for the provided name
*/
Translator get(String name);
/**
- * Finds a {@link Translator} that is appropriate to the given type, which is usually obtained via {@link
- * org.apache.tapestry5.Binding#getBindingType()}. Performs an inheritanced-based search for the best match.
- *
- * @param valueType the type of value for which a default translator is needed
+ * Finds a {@link Translator} that is appropriate to the given type, which is usually obtained via
+ * {@link org.apache.tapestry5.Binding#getBindingType()}. Performs an inheritance-based search for the best match,
+ * among the <em>standard</em> translator (not alternates).
+ *
+ * @param valueType
+ * the type of value for which a default translator is needed
* @return the matching translator, or null if no match can be found
*/
Translator findByType(Class valueType);
/**
- * Finds a {@link Translator} that is appropriate to the given type, which is usually obtained via {@link
- * org.apache.tapestry5.Binding#getBindingType()}. Performs an inheritanced-based search for the best match.
- *
- * @param valueType the type of value for which a default translator is needed
+ * Finds a {@link Translator} that is appropriate to the given type, which is usually obtained via
+ * {@link org.apache.tapestry5.Binding#getBindingType()}. Performs an inheritance-based search for the best match,
+ * among the <em>standard</em> translators (not alternates).
+ *
+ * @param valueType
+ * the type of value for which a default translator is needed
* @return the matching translator
- * @throws IllegalArgumentException if no known validator matches the provided type
+ * @throws IllegalArgumentException
+ * if no standard validator matches the provided type
*/
Translator getByType(Class valueType);
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java?rev=939358&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java Thu Apr 29 16:11:11 2010
@@ -0,0 +1,51 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// 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 org.apache.tapestry5.internal.services;
+
+import java.util.Map;
+
+import org.apache.tapestry5.Translator;
+import org.apache.tapestry5.internal.test.InternalBaseTestCase;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.testng.annotations.Test;
+
+@SuppressWarnings("unchecked")
+public class TranslatorAlternatesSourceImplTest extends InternalBaseTestCase
+{
+ @Test
+ public void name_mismatch()
+ {
+ Translator t = mockTranslator();
+
+ train_getName(t, "barney");
+
+ Map<String, Translator> configuration = CollectionFactory.newMap();
+
+ configuration.put("Fred", t);
+
+ replay();
+
+ try
+ {
+ new TranslatorAlternatesSourceImpl(configuration);
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertEquals(ex.getMessage(),
+ "Contribution key 'Fred' does not match 'barney' (the name of the corresponding Translator).");
+ }
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorAlternatesSourceImplTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java?rev=939358&r1=939357&r2=939358&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java Thu Apr 29 16:11:11 2010
@@ -36,6 +36,7 @@ import org.testng.annotations.BeforeMeth
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
+@SuppressWarnings("unchecked")
public class TranslatorSourceImplTest extends InternalBaseTestCase
{
private TranslatorSource source;
@@ -98,6 +99,82 @@ public class TranslatorSourceImplTest ex
}
@Test
+ public void name_collision_with_standard_translators()
+ {
+ Translator t1 = mockTranslator("fred", Integer.class);
+ Translator t2 = mockTranslator("fred", Long.class);
+
+ Map<Class, Translator> configuration = CollectionFactory.newMap();
+ configuration.put(Integer.class, t1);
+ configuration.put(Long.class, t2);
+
+ replay();
+
+ try
+ {
+ new TranslatorSourceImpl(configuration);
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertMessageContains(
+ ex,
+ "Two different Translators contributed to the TranslatorSource service use the same translator name: 'fred'.",
+ "Translator names must be unique.");
+ }
+
+ verify();
+ }
+
+ @Test
+ public void get_alternate_translator_by_name()
+ {
+ Translator t1 = mockTranslator("fred", Integer.class);
+ Translator t2 = mockTranslator();
+
+ Map<Class, Translator> configuration = newConfiguration(Integer.class, t1);
+
+ Map<String, Translator> alternates = CollectionFactory.newMap();
+ alternates.put("barney", t2);
+
+ replay();
+
+ TranslatorSource source = new TranslatorSourceImpl(configuration, alternates);
+
+ assertSame(source.get("barney"), t2);
+
+ verify();
+ }
+
+ @Test
+ public void name_collision_between_standard_and_alternate_translator()
+ {
+ Translator t1 = mockTranslator("fred", Integer.class);
+ Translator t2 = mockTranslator();
+
+ Map<Class, Translator> configuration = newConfiguration(Integer.class, t1);
+
+ Map<String, Translator> alternates = CollectionFactory.newMap();
+ alternates.put("fred", t2);
+
+ replay();
+
+ try
+ {
+ new TranslatorSourceImpl(configuration, alternates);
+ unreachable();
+ }
+ catch (RuntimeException ex)
+ {
+ assertEquals(
+ ex.getMessage(),
+ "Translator 'fred' contributed to the TranslatorAlternatesSource service has the same name as a standard Translator contributed to the TranslatorSource service.");
+ }
+
+ verify();
+ }
+
+ @Test
public void unknown_translator_is_failure()
{
Translator fred = mockTranslator("fred", String.class);