You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2007/06/18 03:21:21 UTC

svn commit: r548154 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/corelib/base/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/internal/ main/java/org/apa...

Author: hlship
Date: Sun Jun 17 18:21:19 2007
New Revision: 548154

URL: http://svn.apache.org/viewvc?view=rev&rev=548154
Log:
TAPESTRY-1480: Implement Radio component

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/RadioContainer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/EnumValueEncoderFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/GenericValueEncoderFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/StringValueEncoder.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ValueEncoderSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ioc/services/ComponentDefaultProvider.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderFactory.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/RadioDemo.html
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/RadioDemo.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImplTest.java
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/DefaultComponentParameterBindingSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/DefaultComponentParameterBindingSource.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/DefaultComponentParameterBindingSourceImplTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ValueEncoder.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Output.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/OutputRaw.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationGlobalsImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/Start.html
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/TapestryInternalUtilsTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResourcesCommon.java Sun Jun 17 18:21:19 2007
@@ -25,7 +25,8 @@
 import org.apache.tapestry.services.ComponentSource;
 
 /**
- * Operations shared by {@link ComponentResources} and {@link ComponentPageElement}.
+ * Operations shared by the public {@link ComponentResources} interface and
+ * {@link ComponentPageElement} interface (on the internal side).
  */
 public interface ComponentResourcesCommon extends Locatable
 {
@@ -40,7 +41,6 @@
      * periods. In addition, nested ids are always all lower case. I.e., "foo.bar.baz". Returns null
      * for a page.
      */
-
     String getNestedId();
 
     /**
@@ -71,7 +71,7 @@
     /**
      * Returns a string consisting of the fully qualified class name of the containing page, and the
      * {@link #getNestedId() nested id} of this component, separated by a colon. I.e.,
-     * "com.foo.pages.MyPage:foo.bar.baz". For a page, returns just the page class name.
+     * "MyPage:foo.bar.baz". For a page, returns just the page's logical name.
      * <p>
      * This value is often used to obtain an equivalent component instance in a later request.
      * 
@@ -124,7 +124,7 @@
 
     /**
      * Returns the name of element that represents the component in its template, or null if the
-     * element was provided by a &lt;comp&gt; element.
+     * element was a component type (in the Tapestry namespace).
      * 
      * @return the element name
      */

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/RadioContainer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/RadioContainer.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/RadioContainer.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/RadioContainer.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,48 @@
+// Copyright 2007 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.tapestry;
+
+import org.apache.tapestry.corelib.components.Radio;
+
+/**
+ * A container of {@link Radio} components, used to identify the element name used when rendering
+ * the individual radio buttons (all buttons in a group share the same element name) and to
+ */
+public interface RadioContainer
+{
+    /**
+     * Returns the value used as the name attribute of the rendered element. This value will be
+     * unique within an enclosing form, even if the same component renders multiple times.
+     */
+    String getElementName();
+
+    /**
+     * If true, then all buttons within the container should also be disabled.
+     */
+    boolean isDisabled();
+
+    /**
+     * Converts an object to a client-side string representation of that value.
+     * 
+     * @param value
+     *            to convert (may be null)
+     * @return string representation of the value
+     * @see ValueEncoder#toClient(Object)
+     */
+    String toClient(Object value);
+
+    /** Returns true if the value is the current selected value. */
+    boolean isSelected(Object value);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ValueEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ValueEncoder.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ValueEncoder.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ValueEncoder.java Sun Jun 17 18:21:19 2007
@@ -19,6 +19,10 @@
 /**
  * Used by {@link Select} (and similar components) to encode server side values into client-side
  * strings, and back.
+ * <p>
+ * Most often a custom implementation is needed for entity type objects, where the
+ * {@link #toClient(Object)} method extracts a primary key, and the {@link #toValue(String)}
+ * re-acquires the corresponding entity object.
  * 
  * @see SelectModel
  */

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java Sun Jun 17 18:21:19 2007
@@ -35,9 +35,7 @@
 import org.apache.tapestry.corelib.mixins.DiscardBody;
 import org.apache.tapestry.corelib.mixins.RenderDisabled;
 import org.apache.tapestry.corelib.mixins.RenderInformals;
-import org.apache.tapestry.internal.TapestryInternalUtils;
-import org.apache.tapestry.ioc.Messages;
-import org.apache.tapestry.services.DefaultComponentParameterBindingSource;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
 import org.apache.tapestry.services.FormSupport;
 
 /**
@@ -143,19 +141,11 @@
     private ComponentResources _resources;
 
     @Inject
-    private DefaultComponentParameterBindingSource _defaultBindingSource;
+    private ComponentDefaultProvider _defaultProvider;
 
     final String defaultLabel()
     {
-        Messages containerMessages = _resources.getContainer().getComponentResources()
-                .getMessages();
-
-        String componentId = _resources.getId();
-
-        String key = componentId + "-label";
-
-        return containerMessages.contains(key) ? containerMessages.get(key) : TapestryInternalUtils
-                .toUserPresentable(componentId);
+        return _defaultProvider.defaultLabel(_resources);
     }
 
     public final String getLabel()
@@ -219,7 +209,7 @@
      */
     protected final Binding createDefaultParameterBinding(String parameterName)
     {
-        return _defaultBindingSource.createDefaultBinding(parameterName, _resources);
+        return _defaultProvider.defaultBinding(parameterName, _resources);
     }
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/BeanEditForm.java Sun Jun 17 18:21:19 2007
@@ -32,12 +32,12 @@
 import org.apache.tapestry.beaneditor.PropertyModel;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
 import org.apache.tapestry.services.BeanBlockSource;
-import org.apache.tapestry.services.PropertyEditContext;
 import org.apache.tapestry.services.BeanModelSource;
-import org.apache.tapestry.services.DefaultComponentParameterBindingSource;
 import org.apache.tapestry.services.Environment;
 import org.apache.tapestry.services.FieldValidatorDefaultSource;
+import org.apache.tapestry.services.PropertyEditContext;
 import org.apache.tapestry.services.TranslatorDefaultSource;
 
 /**
@@ -117,14 +117,14 @@
     private Block _blockForProperty;
 
     @Inject
-    private DefaultComponentParameterBindingSource _defaultBindingSource;
-
-    @Inject
     private Environment _environment;
 
     @Inject
     private BeanBlockSource _beanBlockSource;
 
+    @Inject
+    private ComponentDefaultProvider _defaultProvider;
+
     private boolean _mustPopBeanEditContext;
 
     /**
@@ -132,7 +132,7 @@
      */
     Binding defaultObject()
     {
-        return _defaultBindingSource.createDefaultBinding("object", _resources);
+        return _defaultProvider.defaultBinding("object", _resources);
     }
 
     public BeanModel getModel()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Form.java Sun Jun 17 18:21:19 2007
@@ -47,6 +47,7 @@
 import org.apache.tapestry.internal.util.Base64ObjectInputStream;
 import org.apache.tapestry.internal.util.Base64ObjectOutputStream;
 import org.apache.tapestry.internal.util.Holder;
+import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.ActionResponseGenerator;
 import org.apache.tapestry.services.ComponentEventResultProcessor;
@@ -186,6 +187,11 @@
     @Mixin
     private RenderInformals _renderInformals;
 
+    @Inject
+    private ComponentEventResultProcessor _eventResultProcessor;
+
+    private String _name;
+
     public ValidationTracker getDefaultTracker()
     {
         if (_defaultTracker == null) _defaultTracker = new ValidationTrackerImpl();
@@ -295,11 +301,6 @@
         _tracker = _environment.pop(ValidationTracker.class);
     }
 
-    @Inject
-    private ComponentEventResultProcessor _eventResultProcessor;
-
-    private String _name;
-
     @SuppressWarnings("unchecked")
     Object onAction(Object[] context)
     {
@@ -347,6 +348,8 @@
 
             ObjectInputStream ois = null;
 
+            Component component = null;
+
             try
             {
                 ois = new Base64ObjectInputStream(actionsBase64);
@@ -356,9 +359,11 @@
                     String componentId = ois.readUTF();
                     ComponentAction action = (ComponentAction) ois.readObject();
 
-                    Component component = _source.getComponent(componentId);
+                    component = _source.getComponent(componentId);
 
                     action.execute(component);
+
+                    component = null;
                 }
             }
             catch (EOFException ex)
@@ -367,7 +372,7 @@
             }
             catch (Exception ex)
             {
-                throw new RuntimeException(ex);
+                throw new TapestryException(ex.getMessage(), component, ex);
             }
             finally
             {
@@ -412,17 +417,11 @@
         }
         finally
         {
-
             _environment.pop(Heartbeat.class);
             _environment.pop(FormSupport.class);
         }
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.apache.tapestry.corelib.components.FormValidationControl#recordError(java.lang.String)
-     */
     public void recordError(String errorMessage)
     {
         ValidationTracker tracker = _tracker;
@@ -432,12 +431,6 @@
         _tracker = tracker;
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.apache.tapestry.corelib.components.FormValidationControl#recordError(org.apache.tapestry.Field,
-     *      java.lang.String)
-     */
     public void recordError(Field field, String errorMessage)
     {
         ValidationTracker tracker = _tracker;
@@ -447,21 +440,11 @@
         _tracker = tracker;
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.apache.tapestry.corelib.components.FormValidationControl#getHasErrors()
-     */
     public boolean getHasErrors()
     {
         return _tracker.getHasErrors();
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.apache.tapestry.corelib.components.FormValidationControl#isValid()
-     */
     public boolean isValid()
     {
         return !_tracker.getHasErrors();
@@ -474,11 +457,6 @@
         _tracker = tracker;
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see org.apache.tapestry.corelib.components.FormValidationControl#clearErrors()
-     */
     public void clearErrors()
     {
         _tracker.clear();
@@ -491,5 +469,4 @@
     {
         return _name;
     }
-
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Output.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Output.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Output.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Output.java Sun Jun 17 18:21:19 2007
@@ -23,7 +23,7 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.services.DefaultComponentParameterBindingSource;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
 
 /**
  * A component for formatting output. If the component is represented in the template using an
@@ -52,14 +52,14 @@
     private String _elementName;
 
     @Inject
-    private DefaultComponentParameterBindingSource _defaultBindingSource;
+    private ComponentDefaultProvider _defaultProvider;
 
     @Inject
     private ComponentResources _resources;
 
     Binding defaultValue()
     {
-        return _defaultBindingSource.createDefaultBinding("value", _resources);
+        return _defaultProvider.defaultBinding("value", _resources);
     }
 
     boolean beginRender(MarkupWriter writer)
@@ -77,8 +77,7 @@
 
             writer.write(formatted);
 
-            if (_elementName != null)
-                writer.end();
+            if (_elementName != null) writer.end();
         }
 
         return false;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/OutputRaw.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/OutputRaw.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/OutputRaw.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/OutputRaw.java Sun Jun 17 18:21:19 2007
@@ -19,7 +19,7 @@
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.annotations.Inject;
 import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.services.DefaultComponentParameterBindingSource;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
 
 /**
  * Used to output raw markup to the client. Unlike, say, an expansion, the output from OutputRaw is
@@ -38,14 +38,14 @@
     private String _value;
 
     @Inject
-    private DefaultComponentParameterBindingSource _defaultBindingSource;
+    private ComponentDefaultProvider _defaultProvider;
 
     @Inject
     private ComponentResources _resources;
 
     Binding defaultValue()
     {
-        return _defaultBindingSource.createDefaultBinding("value", _resources);
+        return _defaultProvider.defaultBinding("value", _resources);
     }
 
     boolean beginRender(MarkupWriter writer)

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,153 @@
+// Copyright 2007 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.tapestry.corelib.components;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Field;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.PageRenderSupport;
+import org.apache.tapestry.RadioContainer;
+import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.Mixin;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.mixins.DiscardBody;
+import org.apache.tapestry.corelib.mixins.RenderDisabled;
+import org.apache.tapestry.corelib.mixins.RenderInformals;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
+
+/**
+ * A radio button (i.e., &lt;input type="radio"&gt;). Radio buttons <strong>must</strong> operate
+ * within a {@link RadioContainer} (normally, the {@link RadioGroup} component).
+ * <p>
+ * If the value parameter is not bound, then the default value is a property of the container
+ * component whose name matches the Radio component's id.
+ */
+public class Radio implements Field
+{
+    @Environmental
+    private RadioContainer _container;
+
+    /**
+     * The user presentable label for the field. If not provided, a reasonable label is generated
+     * from the component's id, first by looking for a message key named "id-label" (substituting
+     * the component's actual id), then by converting the actual id to a presentable string (for
+     * example, "userId" to "User Id").
+     */
+    @Parameter(defaultPrefix = "literal")
+    private String _label;
+
+    /**
+     * The value associated with this radio button. This is used to determine which radio button
+     * will be selected when the page is rendered, and also becomes the value assigned when the form
+     * is submitted.
+     */
+    @Parameter(required = true, principal = true)
+    private Object _value;
+
+    @Inject
+    private ComponentDefaultProvider _defaultProvider;
+
+    @Inject
+    private ComponentResources _resources;
+
+    @SuppressWarnings("unused")
+    @Mixin
+    private RenderInformals _renderInformals;
+
+    @SuppressWarnings("unused")
+    @Mixin
+    private RenderDisabled _renderDisabled;
+
+    @SuppressWarnings("unused")
+    @Mixin
+    private DiscardBody _discardBody;
+
+    @Inject
+    private PageRenderSupport _pageRenderSupport;
+
+    private String _clientId;
+
+    /**
+     * If true, then the field will render out with a disabled attribute (to turn off client-side
+     * behavior). Further, a disabled field ignores any value in the request when the form is
+     * submitted.
+     */
+    @Parameter("false")
+    private boolean _disabled;
+
+    String defaultLabel()
+    {
+        return _defaultProvider.defaultLabel(_resources);
+    }
+
+    Binding defaultValue()
+    {
+        return _defaultProvider.defaultBinding("value", _resources);
+    }
+
+    /**
+     * Returns the element name from the {@link RadioContainer#getElementName() container}.
+     */
+    public String getElementName()
+    {
+        return _container.getElementName();
+    }
+
+    public String getLabel()
+    {
+        return _label;
+    }
+
+    /**
+     * Returns true if this component has been expressly disabled (via its disabled parameter), or
+     * if the {@link RadioContainer container} has been disabled.
+     */
+    public boolean isDisabled()
+    {
+        return _disabled || _container.isDisabled();
+    }
+
+    public String getClientId()
+    {
+        return _clientId;
+    }
+
+    void beginRender(MarkupWriter writer)
+    {
+        String value = _container.toClient(_value);
+
+        _clientId = _pageRenderSupport.allocateClientId(_resources.getId());
+
+        writer.element(
+                "input",
+                "type",
+                "radio",
+                "id",
+                _clientId,
+                "name",
+                getElementName(),
+                "value",
+                value);
+
+        if (_container.isSelected(_value)) writer.attributes("checked", "checked");
+    }
+
+    void afterRender(MarkupWriter writer)
+    {
+        writer.end();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,178 @@
+// Copyright 2007 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.tapestry.corelib.components;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentAction;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.RadioContainer;
+import org.apache.tapestry.ValueEncoder;
+import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.TapestryInternalUtils;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.services.FormSupport;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.ValueEncoderSource;
+
+public class RadioGroup
+{
+    /**
+     * The property read and updated by the group as a whole.
+     */
+    @Parameter(required = true, principal=true)
+    private Object _value;
+
+    /**
+     * If true, then the field will render out with a disabled attribute (to turn off client-side
+     * behavior). Further, a disabled field ignores any value in the request when the form is
+     * submitted.
+     */
+    @Parameter("false")
+    private boolean _disabled;
+
+    /**
+     * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to
+     * create client-side string values for the different radio button values.
+     * 
+     * @see ValueEncoderSource
+     */
+    @Parameter(required = true)
+    private ValueEncoder _encoder;
+
+    @Inject
+    private ComponentDefaultProvider _defaultProvider;
+
+    @Inject
+    private ComponentResources _resources;
+
+    @Environmental
+    private FormSupport _formSupport;
+
+    @Inject
+    private Environment _environment;
+
+    @Inject
+    private ValueEncoderSource _valueEncoderSource;
+
+    @Inject
+    private Request _request;
+
+    private String _elementName;
+
+    final Binding defaultValue()
+    {
+        return _defaultProvider.defaultBinding("value", _resources);
+    }
+
+    final ValueEncoder defaultEncoder()
+    {
+        return _valueEncoderSource.createEncoder("value", _resources);
+    }
+
+    private static class Setup implements ComponentAction<RadioGroup>
+    {
+        private static final long serialVersionUID = -7984673040135949374L;
+
+        private final String _elementName;
+
+        Setup(String elementName)
+        {
+            _elementName = elementName;
+        }
+
+        public void execute(RadioGroup component)
+        {
+            component.setup(_elementName);
+        }
+    };
+
+    private static final ComponentAction<RadioGroup> PROCESS_SUBMISSION = new ComponentAction<RadioGroup>()
+    {
+        private static final long serialVersionUID = -3857110108918776386L;
+
+        public void execute(RadioGroup component)
+        {
+            component.processSubmission();
+        }
+    };
+
+    private void setup(String elementName)
+    {
+        _elementName = elementName;
+    }
+
+    private void processSubmission()
+    {
+        String clientValue = _request.getParameter(_elementName);
+
+        Object value = _encoder.toValue(clientValue);
+
+        _value = value;
+    }
+
+    /**
+     * Obtains the element name for the group, and stores a {@link RadioContainer} into the
+     * {@link Environment} (so that the {@link Radio} components can find it).
+     */
+    final void setupRender()
+    {
+        String name = _formSupport.allocateElementName(_resources.getId());
+
+        ComponentAction<RadioGroup> action = new Setup(name);
+
+        _formSupport.storeAndExecute(this, action);
+
+        _environment.push(RadioContainer.class, new RadioContainer()
+        {
+            public String getElementName()
+            {
+                return _elementName;
+            }
+
+            public boolean isDisabled()
+            {
+                return _disabled;
+            }
+
+            @SuppressWarnings("unchecked")
+            public String toClient(Object value)
+            {
+                // TODO: Ensure that value is of the expected type?
+
+                return _encoder.toClient(value);
+            }
+
+            public boolean isSelected(Object value)
+            {
+                return TapestryInternalUtils.isEqual(value, _value);
+            }
+
+        });
+
+        _formSupport.store(this, PROCESS_SUBMISSION);
+    }
+
+    /**
+     * Pops the {@link RadioContainer}.
+     */
+    final void afterRender()
+    {
+        _environment.pop(RadioContainer.class);
+    }
+
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java Sun Jun 17 18:21:19 2007
@@ -35,12 +35,20 @@
 import org.apache.tapestry.services.FieldValidatorDefaultSource;
 import org.apache.tapestry.services.FormSupport;
 import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.ValueEncoderFactory;
+import org.apache.tapestry.services.ValueEncoderSource;
 import org.apache.tapestry.util.EnumSelectModel;
-import org.apache.tapestry.util.EnumValueEncoder;
 
 /**
  * Select an item from a list of values, using an [X]HTML &lt;select&gt; element on the client side.
  * An validation decorations will go around the entire &lt;select&gt; element.
+ * <p>
+ * A core part of this component is the {@link ValueEncoder} (the encoder parameter) that is used to
+ * convert between server-side values and client-side strings. In many cases, a {@link ValueEncoder}
+ * can be generated automatically from the type of the value parameter. The
+ * {@link ValueEncoderSource} service provides an encoder in these situations; it can be overriden
+ * by binding the encoder parameter, or extended by contributing a {@link ValueEncoderFactory} into
+ * the service's configuration.
  */
 public final class Select extends AbstractField
 {
@@ -62,25 +70,13 @@
     }
 
     /**
-     * The default encoder encodes strings, passing them to the client and back unchanged.
+     * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to
+     * create client-side string values for the different options.
+     * 
+     * @see ValueEncoderSource
      */
     @Parameter
-    private ValueEncoder _encoder = new ValueEncoder<String>()
-    {
-        public String toClient(String value)
-        {
-            return value;
-        }
-
-        public String toValue(String primaryKey)
-        {
-            // We don't do a conversion here, so it stays a String. When that String is assigned to
-            // _value, it will be coerced to the appropriate type (if possible) or an exception
-            // will be thrown.
-
-            return primaryKey;
-        }
-    };
+    private ValueEncoder _encoder;
 
     @Inject
     private FieldValidatorDefaultSource _fieldValidatorDefaultSource;
@@ -114,6 +110,9 @@
     @Parameter(required = true, principal = true)
     private Object _value;
 
+    @Inject
+    private ValueEncoderSource _valueEncoderSource;
+
     @Override
     protected void processSubmission(FormSupport formSupport, String elementName)
     {
@@ -149,13 +148,7 @@
     @SuppressWarnings("unchecked")
     ValueEncoder defaultEncoder()
     {
-        Class valueType = _resources.getBoundType("value");
-
-        if (valueType == null) return null;
-
-        if (Enum.class.isAssignableFrom(valueType)) return new EnumValueEncoder(valueType);
-
-        return null;
+        return _valueEncoderSource.createEncoder("value", _resources);
     }
 
     @SuppressWarnings("unchecked")
@@ -213,5 +206,10 @@
     void setValue(Object value)
     {
         _value = value;
+    }
+
+    void setValueEncoder(ValueEncoder encoder)
+    {
+        _encoder = encoder;
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/TapestryInternalUtils.java Sun Jun 17 18:21:19 2007
@@ -473,4 +473,22 @@
             throw new RuntimeException(ex);
         }
     }
+
+    /**
+     * Determines if the two values are equal. They are equal if they are the exact same value
+     * (including if they are both null). Otherwise standard equals() comparison is used.
+     * 
+     * @param <T>
+     * @param left
+     * @param right
+     * @return
+     */
+    public static <T> boolean isEqual(T left, T right)
+    {
+        if (left == right) return true;
+
+        if (left == null) return right == null;
+
+        return left.equals(right);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationGlobalsImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationGlobalsImpl.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationGlobalsImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ApplicationGlobalsImpl.java Sun Jun 17 18:21:19 2007
@@ -25,8 +25,6 @@
 
     private Context _context;
 
-    private String _applicationRootPackage;
-
     public void store(ServletContext context)
     {
         _servletContext = context;
@@ -45,15 +43,5 @@
     public void store(Context context)
     {
         _context = context;
-    }
-
-    public String getApplicationRootPackage()
-    {
-        return _applicationRootPackage;
-    }
-
-    public void store(String applicationRootPackage)
-    {
-        _applicationRootPackage = applicationRootPackage;
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImpl.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImpl.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,72 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.internal.TapestryInternalUtils;
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
+import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.services.BindingSource;
+
+public class ComponentDefaultProviderImpl implements ComponentDefaultProvider
+{
+    private final PropertyAccess _propertyAccess;
+
+    private final BindingSource _bindingSource;
+
+    public ComponentDefaultProviderImpl(PropertyAccess propertyAccess, BindingSource bindingSource)
+    {
+        _propertyAccess = propertyAccess;
+        _bindingSource = bindingSource;
+    }
+
+    public String defaultLabel(ComponentResources resources)
+    {
+        String componentId = resources.getId();
+        String key = componentId + "-label";
+
+        Messages containerMessages = resources.getContainerResources().getMessages();
+
+        if (containerMessages.contains(key)) return containerMessages.get(key);
+
+        return TapestryInternalUtils.toUserPresentable(componentId);
+    }
+
+    public Binding defaultBinding(String parameterName, ComponentResources componentResources)
+    {
+        String componentId = componentResources.getId();
+
+        Component container = componentResources.getContainer();
+
+        // Only provide a default binding if the container actually contains the property.
+        // This sets up an error condition for when the parameter is not bound, and
+        // the binding can't be deduced.
+
+        if (_propertyAccess.getAdapter(container).getPropertyAdapter(componentId) == null)
+            return null;
+
+        ComponentResources containerResources = componentResources.getContainerResources();
+
+        return _bindingSource.newBinding(
+                "default " + parameterName,
+                containerResources,
+                TapestryConstants.PROP_BINDING_PREFIX,
+                componentId);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/EnumValueEncoderFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/EnumValueEncoderFactory.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/EnumValueEncoderFactory.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/EnumValueEncoderFactory.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,32 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.ValueEncoder;
+import org.apache.tapestry.services.ValueEncoderFactory;
+import org.apache.tapestry.util.EnumValueEncoder;
+
+/**
+ * Factory that provides a configured instance of {@link EnumValueEncoder}.
+ * 
+ * @param <E>
+ */
+public class EnumValueEncoderFactory<E extends Enum<E>> implements ValueEncoderFactory<E>
+{
+    public ValueEncoder<E> create(Class<E> type)
+    {
+        return new EnumValueEncoder<E>(type);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/GenericValueEncoderFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/GenericValueEncoderFactory.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/GenericValueEncoderFactory.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/GenericValueEncoderFactory.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,39 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.ValueEncoder;
+import org.apache.tapestry.services.ValueEncoderFactory;
+
+/**
+ * An implementation of {@link ValueEncoderFactory} that returns a pre-wired instance of
+ * {@link ValueEncoder}.
+ * 
+ * @param <V>
+ */
+public class GenericValueEncoderFactory<V> implements ValueEncoderFactory<V>
+{
+    private ValueEncoder<V> _encoder;
+
+    public GenericValueEncoderFactory(ValueEncoder<V> encoder)
+    {
+        _encoder = encoder;
+    }
+
+    public ValueEncoder<V> create(Class<V> type)
+    {
+        return _encoder;
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/StringValueEncoder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/StringValueEncoder.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/StringValueEncoder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/StringValueEncoder.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,33 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.ValueEncoder;
+
+/**
+ * Passes the string value from the server to the client and vice-versa without any translation.
+ */
+public class StringValueEncoder implements ValueEncoder<String>
+{
+    public String toClient(String value)
+    {
+        return value;
+    }
+
+    public String toValue(String clientValue)
+    {
+        return clientValue;
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ValueEncoderSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ValueEncoderSourceImpl.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ValueEncoderSourceImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ValueEncoderSourceImpl.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,57 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
+import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
+
+import java.util.Map;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ValueEncoder;
+import org.apache.tapestry.internal.events.InvalidationListener;
+import org.apache.tapestry.ioc.util.StrategyRegistry;
+import org.apache.tapestry.services.ValueEncoderFactory;
+import org.apache.tapestry.services.ValueEncoderSource;
+
+public class ValueEncoderSourceImpl implements ValueEncoderSource, InvalidationListener
+{
+    private final StrategyRegistry<ValueEncoderFactory> _registry;
+
+    public ValueEncoderSourceImpl(Map<Class, ValueEncoderFactory> configuration)
+    {
+        _registry = StrategyRegistry.newInstance(ValueEncoderFactory.class, configuration);
+    }
+
+    @SuppressWarnings("unchecked")
+    public ValueEncoder createEncoder(String parameterName, ComponentResources resources)
+    {
+        notBlank(parameterName, "parameterName");
+        notNull(resources, "resources");
+
+        Class parameterType = resources.getBoundType(parameterName);
+
+        if (parameterType == null) return null;
+
+        ValueEncoderFactory factory = _registry.get(parameterType);
+
+        return factory.create(parameterType);
+    }
+
+    public void objectWasInvalidated()
+    {
+        _registry.clearCache();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ioc/services/ComponentDefaultProvider.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ioc/services/ComponentDefaultProvider.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ioc/services/ComponentDefaultProvider.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ioc/services/ComponentDefaultProvider.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,49 @@
+// Copyright 2007 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.tapestry.ioc.services;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ComponentResourcesCommon;
+import org.apache.tapestry.Field;
+
+/**
+ * A service that can be injected into a component to provide common defaults for various
+ * parameters.
+ */
+public interface ComponentDefaultProvider
+{
+    /**
+     * Computes the default label for the component (which will generally be a {@link Field}).
+     * 
+     * @param resources
+     * @return the label, either extracted from the component's container's message catalog, or
+     *         derived from the component's {@link ComponentResourcesCommon#getId()}.
+     */
+    String defaultLabel(ComponentResources resources);
+
+    /**
+     * Checks to see if the container of the component (identified by its resources) contains a
+     * property matching the component's id. If so, a binding for that property is returned. This is
+     * usually the default for a {@link Field}'s value parameter (or equivalent).
+     * 
+     * @param parameterName
+     *            the name of the parameter
+     * @param resources
+     *            the resources of the component for which a binding is needed
+     * @return the binding, or null if the container does not have a matching property
+     */
+    Binding defaultBinding(String parameterName, ComponentResources resources);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ApplicationGlobals.java Sun Jun 17 18:21:19 2007
@@ -28,8 +28,4 @@
     void store(Context context);
 
     Context getContext();
-
-    void store(String applicationRootPackage);
-
-    String getApplicationRootPackage();
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Sun Jun 17 18:21:19 2007
@@ -85,6 +85,7 @@
 import org.apache.tapestry.internal.services.CommonResourcesInjectionProvider;
 import org.apache.tapestry.internal.services.ComponentActionDispatcher;
 import org.apache.tapestry.internal.services.ComponentClassResolverImpl;
+import org.apache.tapestry.internal.services.ComponentDefaultProviderImpl;
 import org.apache.tapestry.internal.services.ComponentInstanceResultProcessor;
 import org.apache.tapestry.internal.services.ComponentInstantiatorSource;
 import org.apache.tapestry.internal.services.ComponentInvocationMap;
@@ -99,12 +100,14 @@
 import org.apache.tapestry.internal.services.DefaultValidationDelegateCommand;
 import org.apache.tapestry.internal.services.DocumentScriptBuilder;
 import org.apache.tapestry.internal.services.DocumentScriptBuilderImpl;
+import org.apache.tapestry.internal.services.EnumValueEncoderFactory;
 import org.apache.tapestry.internal.services.EnvironmentImpl;
 import org.apache.tapestry.internal.services.EnvironmentalShadowBuilderImpl;
 import org.apache.tapestry.internal.services.EnvironmentalWorker;
 import org.apache.tapestry.internal.services.FieldValidatorDefaultSourceImpl;
 import org.apache.tapestry.internal.services.FieldValidatorSourceImpl;
 import org.apache.tapestry.internal.services.FlashPersistentFieldStrategy;
+import org.apache.tapestry.internal.services.GenericValueEncoderFactory;
 import org.apache.tapestry.internal.services.HeartbeatImpl;
 import org.apache.tapestry.internal.services.InjectBlockWorker;
 import org.apache.tapestry.internal.services.InjectComponentWorker;
@@ -130,6 +133,8 @@
 import org.apache.tapestry.internal.services.ParameterWorker;
 import org.apache.tapestry.internal.services.PersistWorker;
 import org.apache.tapestry.internal.services.PersistentFieldManagerImpl;
+import org.apache.tapestry.internal.services.StringValueEncoder;
+import org.apache.tapestry.internal.services.ValueEncoderSourceImpl;
 import org.apache.tapestry.internal.services.PropertyConduitSourceImpl;
 import org.apache.tapestry.internal.services.RenderCommandWorker;
 import org.apache.tapestry.internal.services.RequestGlobalsImpl;
@@ -155,7 +160,6 @@
 import org.apache.tapestry.internal.services.UpdateListenerHub;
 import org.apache.tapestry.internal.services.ValidationConstraintGeneratorImpl;
 import org.apache.tapestry.internal.services.ValidationMessagesSourceImpl;
-import org.apache.tapestry.internal.structure.DefaultComponentParameterBindingSourceImpl;
 import org.apache.tapestry.ioc.AnnotationProvider;
 import org.apache.tapestry.ioc.Configuration;
 import org.apache.tapestry.ioc.Location;
@@ -176,6 +180,7 @@
 import org.apache.tapestry.ioc.services.ClassFactory;
 import org.apache.tapestry.ioc.services.Coercion;
 import org.apache.tapestry.ioc.services.CoercionTuple;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
 import org.apache.tapestry.ioc.services.PipelineBuilder;
 import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.ioc.services.PropertyShadowBuilder;
@@ -227,6 +232,7 @@
         binder.bind(ComponentSource.class, ComponentSourceImpl.class);
         binder.bind(BeanModelSource.class, BeanModelSourceImpl.class);
         binder.bind(BeanBlockSource.class, BeanBlockSourceImpl.class);
+        binder.bind(ComponentDefaultProvider.class, ComponentDefaultProviderImpl.class);
     }
 
     public static MarkupWriterFactory build(final ComponentInvocationMap componentInvocationMap)
@@ -1182,12 +1188,6 @@
         return new ComponentInstanceResultProcessor(_requestPageCache, _linkFactory, log);
     }
 
-    public DefaultComponentParameterBindingSource buildDefaultComponentParameterBindingSource(
-            BindingSource bindingSource)
-    {
-        return new DefaultComponentParameterBindingSourceImpl(_propertyAccess, bindingSource);
-    }
-
     /**
      * Ordered contributions to the MasterDispatcher service allow different URL matching strategies
      * to occur.
@@ -1290,7 +1290,8 @@
 
         configuration.add(String.class, new StringResultProcessor(_requestPageCache, _linkFactory));
 
-        configuration.add(Class.class, new ClassResultProcessor(componentClassResolver, _requestPageCache, _linkFactory));
+        configuration.add(Class.class, new ClassResultProcessor(componentClassResolver,
+                _requestPageCache, _linkFactory));
 
         configuration.add(Component.class, componentInstanceProcessor);
 
@@ -1470,5 +1471,31 @@
     public void contributeValidationMessagesSource(Configuration<String> configuration)
     {
         configuration.add("org/apache/tapestry/internal/ValidationMessages");
+    }
+
+    public ValueEncoderSource build(Map<Class, ValueEncoderFactory> configuration)
+    {
+        ValueEncoderSourceImpl service = new ValueEncoderSourceImpl(configuration);
+
+        _componentInstantiatorSource.addInvalidationListener(service);
+
+        return service;
+    }
+
+    /**
+     * Contributes {@link ValueEncoderFactory}s for types:
+     * <ul>
+     * <li>String
+     * <li>Enum
+     * </ul>
+     * 
+     * @param configuration
+     */
+    @SuppressWarnings("unchecked")
+    public static void contributeValueEncoderSource(
+            MappedConfiguration<Class, ValueEncoderFactory> configuration)
+    {
+        configuration.add(String.class, new GenericValueEncoderFactory(new StringValueEncoder()));
+        configuration.add(Enum.class, new EnumValueEncoderFactory());
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderFactory.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderFactory.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderFactory.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,22 @@
+// Copyright 2007 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.tapestry.services;
+
+import org.apache.tapestry.ValueEncoder;
+
+public interface ValueEncoderFactory<V>
+{
+    ValueEncoder<V> create(Class<V> type);
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderSource.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderSource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ValueEncoderSource.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,35 @@
+// Copyright 2007 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.tapestry.services;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ValueEncoder;
+
+/**
+ * A source for value encoders based on a property type.
+ */
+public interface ValueEncoderSource
+{
+    /**
+     * Creates a value encoder based on the <em>type</em> of the named parameter.
+     * 
+     * @param parameterName
+     *            the name of the parameter whose type is used to locate a PKE factory
+     * @param resources
+     *            the resources of the component, from which parameter and its type are extracted
+     * @return the value encoder
+     */
+    ValueEncoder createEncoder(String parameterName, ComponentResources resources);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt Sun Jun 17 18:21:19 2007
@@ -13,6 +13,8 @@
   Progress on Tapestry 5 is really taking off. This space lists some cool new features that have been added
   recently.
   
+  * A Radio button component has been added.
+  
   * A file upload form component has been added (in a new library: {{{../tapestry-upload/}tapestry-upload}}). 
   
   * The BeanEditForm component can now create the object is edits.

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/RadioDemo.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/RadioDemo.html?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/RadioDemo.html (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/RadioDemo.html Sun Jun 17 18:21:19 2007
@@ -0,0 +1,27 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+
+  <h1>Radio Demo</h1>
+
+  <p>Choose a department: </p>
+
+  <t:form>
+    <t:radiogroup t:id="department">
+      <t:loop source="departments" value="loopValue">
+        <p>
+          <t:radio t:id="radio" value="loopValue" label="prop:label"/>
+          <t:label for="radio"/>
+        </p>
+      </t:loop>
+    </t:radiogroup>
+    <p>
+      <input type="submit" value="Update"/>
+    </p>
+  </t:form>
+
+
+  <t:if test="department">
+    <hr/>
+    Selected department: ${department}
+  </t:if>
+
+</html>

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/Start.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/Start.html?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/Start.html (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/WEB-INF/Start.html Sun Jun 17 18:21:19 2007
@@ -125,15 +125,16 @@
             <t:pagelink page="attributeExpansionsDemo">Attribute Expansions Demo</t:pagelink> -- use
             expansions inside attributes of ordinary elements </li>
           <li>
-            <t:pagelink page="PaletteDemo">Palette Demo</t:pagelink> -- multiple selection component
-          </li>
+            <t:pagelink page="PaletteDemo">Palette Demo</t:pagelink> -- multiple selection component </li>
           <li>
             <t:pagelink page="ReturnTypes">Return Types</t:pagelink> -- Tests various event handler
-            return types
-          </li>
+            return types </li>
           <li>
-            <t:pagelink page="FormEncodingType">Form Encoding Type</t:pagelink> --- Test ability to set an encoding type for a Form
-          </li>
+            <t:pagelink page="FormEncodingType">Form Encoding Type</t:pagelink> -- Test ability to
+            set an encoding type for a Form </li>
+          <li>
+            <t:pagelink page="RadioDemo">RadioDemo</t:pagelink> -- Use of the RadioGroup and Radio
+            components. </li>
         </ul>
       </td>
     </tr>

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java Sun Jun 17 18:21:19 2007
@@ -33,6 +33,7 @@
 import org.apache.tapestry.internal.SelectModelImpl;
 import org.apache.tapestry.internal.TapestryInternalUtils;
 import org.apache.tapestry.internal.services.MarkupWriterImpl;
+import org.apache.tapestry.internal.services.StringValueEncoder;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import org.testng.annotations.Test;
@@ -43,6 +44,7 @@
  */
 public class SelectTest extends InternalBaseTestCase
 {
+
     @Test
     public void empty_model()
     {
@@ -65,8 +67,7 @@
         {
             int length = reader.read(buffer);
 
-            if (length < 0)
-                break;
+            if (length < 0) break;
 
             builder.append(buffer, 0, length);
         }
@@ -85,6 +86,7 @@
         Select select = new Select();
 
         select.setModel(new SelectModelImpl(null, options));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("barney");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
@@ -109,6 +111,7 @@
         Select select = new Select();
 
         select.setModel(new SelectModelImpl(null, options));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("barney");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
@@ -133,6 +136,7 @@
         Select select = new Select();
 
         select.setModel(new SelectModelImpl(null, options));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("barney");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
@@ -150,8 +154,8 @@
     @Test
     public void option_groups() throws Exception
     {
-        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false, TapestryInternalUtils
-                .toOptionModels("Fred,Barney"));
+        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
+                TapestryInternalUtils.toOptionModels("Fred,Barney"));
         OptionGroupModel wives = new OptionGroupModelImpl("Wives", true, TapestryInternalUtils
                 .toOptionModels("Wilma,Betty"));
         List<OptionGroupModel> groupModels = CollectionFactory.newList(husbands, wives);
@@ -159,6 +163,7 @@
         Select select = new Select();
 
         select.setModel(new SelectModelImpl(groupModels, null));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("Fred");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
@@ -175,13 +180,14 @@
     @Test
     public void option_groups_precede_ungroup_options() throws Exception
     {
-        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false, TapestryInternalUtils
-                .toOptionModels("Fred,Barney"));
+        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
+                TapestryInternalUtils.toOptionModels("Fred,Barney"));
 
         Select select = new Select();
 
-        select.setModel(new SelectModelImpl(Collections.singletonList(husbands), TapestryInternalUtils
-                .toOptionModels("Wilma,Betty")));
+        select.setModel(new SelectModelImpl(Collections.singletonList(husbands),
+                TapestryInternalUtils.toOptionModels("Wilma,Betty")));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("Fred");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
@@ -200,12 +206,13 @@
     {
         Map<String, String> attributes = Collections.singletonMap("class", "pixie");
 
-        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false, TapestryInternalUtils
-                .toOptionModels("Fred,Barney"), attributes);
+        OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
+                TapestryInternalUtils.toOptionModels("Fred,Barney"), attributes);
 
         Select select = new Select();
 
         select.setModel(new SelectModelImpl(Collections.singletonList(husbands), null));
+        select.setValueEncoder(new StringValueEncoder());
         select.setValue("Fred");
 
         MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Sun Jun 17 18:21:19 2007
@@ -1031,4 +1031,25 @@
         assertText("//form/@enctype", "x-override");
     }
 
+    @Test
+    public void radio_button_and_group()
+    {
+        open(BASE_URL);
+
+        String update = "//input[@type='submit']";
+
+        clickAndWait("link=RadioDemo");
+
+        click("//label[.='Accounting']");
+
+        clickAndWait(update);
+
+        assertTextPresent("Selected department: ACCOUNTING");
+
+        click("//label[.='Sales And Marketing']");
+
+        clickAndWait(update);
+
+        assertTextPresent("Selected department: SALES_AND_MARKETING");
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/RadioDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/RadioDemo.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/RadioDemo.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/RadioDemo.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,62 @@
+// Copyright 2007 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.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.Inject;
+import org.apache.tapestry.annotations.Persist;
+import org.apache.tapestry.integration.app1.data.Department;
+import org.apache.tapestry.internal.TapestryInternalUtils;
+import org.apache.tapestry.ioc.Messages;
+
+public class RadioDemo
+{
+    @Persist
+    private Department _department;
+
+    private Department _loopValue;
+
+    @Inject
+    private Messages _messages;
+
+    public Department[] getDepartments()
+    {
+        return Department.values();
+    }
+
+    public Department getDepartment()
+    {
+        return _department;
+    }
+
+    public Department getLoopValue()
+    {
+        return _loopValue;
+    }
+
+    public void setDepartment(Department department)
+    {
+        _department = department;
+    }
+
+    public void setLoopValue(Department loopValue)
+    {
+        _loopValue = loopValue;
+    }
+
+    public String getLabel()
+    {
+        return TapestryInternalUtils.getLabelForEnum(_messages, _loopValue);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/TapestryInternalUtilsTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/TapestryInternalUtilsTest.java?view=diff&rev=548154&r1=548153&r2=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/TapestryInternalUtilsTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/TapestryInternalUtilsTest.java Sun Jun 17 18:21:19 2007
@@ -434,4 +434,33 @@
 
         assertEquals(sorted, Arrays.asList("first", "second"));
     }
+
+    @Test
+    public void null_equals_null()
+    {
+        assertTrue(TapestryInternalUtils.isEqual(null, null));
+    }
+
+    @Test
+    public void non_null_never_equals_null()
+    {
+        assertFalse(TapestryInternalUtils.isEqual(this, null));
+    }
+
+    @Test
+    public void same_is_equal()
+    {
+        assertTrue(TapestryInternalUtils.isEqual(this, this));
+    }
+
+    @Test
+    public void is_equal_with_objects()
+    {
+        String left = "left";
+        String right = "right";
+
+        assertFalse(TapestryInternalUtils.isEqual(left, right));
+        assertTrue(TapestryInternalUtils.isEqual(left, new String(left)));
+    }
+
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImplTest.java?view=auto&rev=548154
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/ComponentDefaultProviderImplTest.java Sun Jun 17 18:21:19 2007
@@ -0,0 +1,178 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.Messages;
+import org.apache.tapestry.ioc.services.ClassPropertyAdapter;
+import org.apache.tapestry.ioc.services.ComponentDefaultProvider;
+import org.apache.tapestry.ioc.services.PropertyAccess;
+import org.apache.tapestry.ioc.services.PropertyAdapter;
+import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.services.BindingSource;
+import org.testng.annotations.Test;
+
+public class ComponentDefaultProviderImplTest extends InternalBaseTestCase
+{
+    @Test
+    public void default_label_key_exists()
+    {
+        ComponentResources resources = mockComponentResources();
+        ComponentResources container = mockComponentResources();
+        Messages messages = mockMessages();
+
+        String componentId = "myfield";
+        String key = componentId + "-label";
+        String message = "My Lovely Field";
+
+        train_getId(resources, componentId);
+        train_getContainerResources(resources, container);
+        train_getMessages(container, messages);
+        train_contains(messages, key, true);
+        train_get(messages, key, message);
+
+        replay();
+
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null);
+
+        assertSame(provider.defaultLabel(resources), message);
+
+        verify();
+    }
+
+    @Test
+    public void default_label_key_missing()
+    {
+        ComponentResources resources = mockComponentResources();
+        ComponentResources container = mockComponentResources();
+        Messages messages = mockMessages();
+
+        String componentId = "myField";
+        String key = componentId + "-label";
+
+        train_getId(resources, componentId);
+        train_getContainerResources(resources, container);
+        train_getMessages(container, messages);
+        train_contains(messages, key, false);
+
+        replay();
+
+        ComponentDefaultProvider provider = new ComponentDefaultProviderImpl(null, null);
+
+        assertEquals(provider.defaultLabel(resources), "My Field");
+
+        verify();
+    }
+
+    @Test
+    public void no_matching_property_for_default()
+    {
+        String parameterName = "myparam";
+
+        String id = "mycomponentid";
+
+        ComponentResources resources = mockComponentResources();
+        Component container = mockComponent();
+        PropertyAccess access = newPropertyAccess();
+        ClassPropertyAdapter classPropertyAdapter = newClassPropertyAdapter();
+        BindingSource bindingSource = mockBindingSource();
+
+        train_getId(resources, id);
+        train_getContainer(resources, container);
+
+        train_getAdapter(access, container, classPropertyAdapter);
+        train_getPropertyAdapter(classPropertyAdapter, id, null);
+
+        replay();
+
+        ComponentDefaultProvider source = new ComponentDefaultProviderImpl(access, bindingSource);
+
+        assertNull(source.defaultBinding(parameterName, resources));
+
+        verify();
+    }
+
+    @Test
+    public void default_property_exists()
+    {
+        String parameterName = "myparam";
+
+        String id = "mycomponentid";
+
+        ComponentResources resources = mockComponentResources();
+        Component container = mockComponent();
+        PropertyAccess access = newPropertyAccess();
+        ClassPropertyAdapter classPropertyAdapter = newClassPropertyAdapter();
+        PropertyAdapter propertyAdapter = newPropertyAdapter();
+        BindingSource bindingSource = mockBindingSource();
+        Binding binding = mockBinding();
+        ComponentResources containerResources = mockComponentResources();
+
+        train_getId(resources, id);
+        train_getContainer(resources, container);
+
+        train_getAdapter(access, container, classPropertyAdapter);
+        train_getPropertyAdapter(classPropertyAdapter, id, propertyAdapter);
+
+        train_getContainerResources(resources, containerResources);
+
+        train_newBinding(
+                bindingSource,
+                "default myparam",
+                containerResources,
+                TapestryConstants.PROP_BINDING_PREFIX,
+                id,
+                binding);
+
+        replay();
+
+        ComponentDefaultProvider source = new ComponentDefaultProviderImpl(access, bindingSource);
+
+        assertSame(source.defaultBinding(parameterName, resources), binding);
+
+        verify();
+    }
+
+    protected final PropertyAdapter newPropertyAdapter()
+    {
+        return newMock(PropertyAdapter.class);
+    }
+
+    protected final ClassPropertyAdapter newClassPropertyAdapter()
+    {
+        return newMock(ClassPropertyAdapter.class);
+    }
+
+    protected final PropertyAccess newPropertyAccess()
+    {
+        return newMock(PropertyAccess.class);
+    }
+
+    protected final void train_getPropertyAdapter(ClassPropertyAdapter classPropertyAdapter,
+            String propertyName, PropertyAdapter propertyAdapter)
+    {
+        expect(classPropertyAdapter.getPropertyAdapter(propertyName)).andReturn(propertyAdapter)
+                .atLeastOnce();
+    }
+
+    protected final void train_getAdapter(PropertyAccess access, Object object,
+            ClassPropertyAdapter classPropertyAdapter)
+    {
+        expect(access.getAdapter(object)).andReturn(classPropertyAdapter);
+    }
+}