Author: hlship
Date: Sat Jan  5 18:05:39 2008
New Revision: 609251

URL: http://svn.apache.org/viewvc?rev=609251&view=rev
Log:
TAPESTRY-1830: Add ability to store temporary data without having to define new 
properties

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBinding.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBindingFactory.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorker.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/VarBindingDemo.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorkerTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app1/pages/VarBindingDemo.tml
Removed:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/ContentType.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/util/ContentTypeTest.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/pages/ExceptionReport.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupWriterFactory.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.tml
    
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt
    tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Start.tml
    
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/integration/app1/pages/ReturnTypes.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/InternalUtils.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/InternalUtilsTest.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/ComponentResources.java
 Sat Jan  5 18:05:39 2008
@@ -127,4 +127,21 @@
      */
     Block getBlockParameter(String parameterName);
 
+    /**
+     * Returns a previously stored render variable.
+     *
+     * @param name of the variable (case will be ignored)
+     * @return the variable's value
+     * @throws IllegalArgumentException if the name doesn't correspond to a 
stored value
+     */
+    Object getRenderVariable(String name);
+
+    /**
+     * Stores a render variable, accessible with the provided name.
+     *
+     * @param name  of value to store
+     * @param value value to store (may not be null)
+     * @throws IllegalStateException if the component is not currently 
rendering
+     */
+    void storeRenderVariable(String name, Object value);
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/pages/ExceptionReport.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/pages/ExceptionReport.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/pages/ExceptionReport.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/pages/ExceptionReport.java
 Sat Jan  5 18:05:39 2008
@@ -38,8 +38,6 @@
 
     private String _propertyName;
 
-    private String _frame;
-
     private String _attributeName;
 
     @Inject
@@ -68,16 +66,6 @@
     public void setInfo(ExceptionInfo info)
     {
         _info = info;
-    }
-
-    public String getFrame()
-    {
-        return _frame;
-    }
-
-    public void setFrame(String frame)
-    {
-        _frame = frame;
     }
 
     public String getPropertyName()

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/InternalComponentResources.java
 Sat Jan  5 18:05:39 2008
@@ -72,4 +72,9 @@
      * to the [EMAIL PROTECTED] PersistentFieldManager}.
      */
     void persistFieldChange(String fieldName, Object newValue);
+
+    /**
+     * Allows the resources to cleanup any render-time only data.
+     */
+    void postRenderCleanup();
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBinding.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBinding.java?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBinding.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBinding.java
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,70 @@
+// Copyright 2008 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.bindings;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ioc.Location;
+
+public class RenderVariableBinding extends AbstractBinding
+{
+    private final String _description;
+    private final ComponentResources _resources;
+    private final String _name;
+
+    public RenderVariableBinding(String description, ComponentResources 
resources, String name, Location location)
+    {
+        super(location);
+
+        _description = description;
+        _resources = resources;
+        _name = name;
+    }
+
+    @Override
+    public void set(Object value)
+    {
+        _resources.storeRenderVariable(_name, value);
+    }
+
+    /**
+     * Returns false, render variables are always variable.
+     */
+    @Override
+    public boolean isInvariant()
+    {
+        return false;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("RenderVariable[%s %s]", _description, _name);
+    }
+
+
+    public Object get()
+    {
+        return _resources.getRenderVariable(_name);
+    }
+
+    /**
+     * Always returns Object since we don't (statically) know the type of 
object.
+     */
+    @Override
+    public Class getBindingType()
+    {
+        return Object.class;
+    }
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBindingFactory.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBindingFactory.java?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBindingFactory.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/bindings/RenderVariableBindingFactory.java
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,29 @@
+// Copyright 2008 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.bindings;
+
+import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.ioc.Location;
+import org.apache.tapestry.services.BindingFactory;
+
+public class RenderVariableBindingFactory implements BindingFactory
+{
+    public Binding newBinding(String description, ComponentResources 
container, ComponentResources component,
+                              String expression, Location location)
+    {
+        return new RenderVariableBinding(description, container, expression, 
location);
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InternalClassTransformationImpl.java
 Sat Jan  5 18:05:39 2008
@@ -1500,4 +1500,8 @@
                 .getMediumDescription(), sourceFile, lineNumber);
     }
 
+    public boolean isRootTransformation()
+    {
+        return _parentTransformation == null;
+    }
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorker.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorker.java?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorker.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorker.java
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,37 @@
+// Copyright 2008 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.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.TransformConstants;
+
+/**
+ * Extends a <em>root</em> component class' postRenderCleanup() method to 
invoke
+ * [EMAIL PROTECTED] 
org.apache.tapestry.internal.InternalComponentResources#postRenderCleanup()}.
+ */
+public class InvokePostRenderCleanupOnResourcesWorker implements 
ComponentClassTransformWorker
+{
+    public void transform(ClassTransformation transformation, 
MutableComponentModel model)
+    {
+        if (!transformation.isRootTransformation()) return;
+
+        String resourcesFieldName = transformation.getResourcesFieldName();
+
+        
transformation.extendMethod(TransformConstants.POST_RENDER_CLEANUP_SIGNATURE,
+                                    resourcesFieldName + 
".postRenderCleanup();");
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
 Sat Jan  5 18:05:39 2008
@@ -24,6 +24,8 @@
 import org.apache.tapestry.ioc.Resource;
 import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import static 
org.apache.tapestry.ioc.internal.util.CollectionFactory.newCaseInsensitiveMap;
+import org.apache.tapestry.ioc.internal.util.Defense;
+import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.internal.util.TapestryException;
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.model.ComponentModel;
@@ -61,6 +63,9 @@
 
     private Messages _messages;
 
+    // Case insensitive
+    private Map<String, Object> _renderVariables;
+
     public InternalComponentResourcesImpl(ComponentPageElement element, 
ComponentResources containerResources,
                                           Instantiator componentInstantiator, 
TypeCoercer typeCoercer,
                                           ComponentMessagesSource 
messagesSource,
@@ -376,5 +381,34 @@
         }
 
         return result;
+    }
+
+    public Object getRenderVariable(String name)
+    {
+        Object result = InternalUtils.get(_renderVariables, name);
+
+        if (result == null) throw new 
IllegalArgumentException(StructureMessages.missingRenderVariable(getCompleteId(),
+                                                                               
                        name,
+                                                                               
                        _renderVariables == null ? null : 
_renderVariables.keySet()));
+
+        return result;
+    }
+
+    public void storeRenderVariable(String name, Object value)
+    {
+        Defense.notBlank(name, "name");
+        Defense.notNull(value, "value");
+
+        if (!_element.isRendering())
+            throw new 
IllegalStateException(StructureMessages.renderVariableSetWhenNotRendering(getCompleteId(),
 name));
+
+        if (_renderVariables == null) _renderVariables = 
CollectionFactory.newCaseInsensitiveMap();
+
+        _renderVariables.put(name, value);
+    }
+
+    public void postRenderCleanup()
+    {
+        if (_renderVariables != null) _renderVariables.clear();
     }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/structure/StructureMessages.java
 Sat Jan  5 18:05:39 2008
@@ -18,9 +18,10 @@
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.internal.util.MessagesImpl;
 
+import java.util.Collection;
 import java.util.List;
 
-class StructureMessages
+final class StructureMessages
 {
     private static final Messages MESSAGES = 
MessagesImpl.forClass(StructureMessages.class);
 
@@ -49,8 +50,7 @@
         return MESSAGES.format("write-parameter-failure", parameterName, 
componentId, cause);
     }
 
-    static String missingMixinForParameter(String componentId, String 
mixinName,
-                                           String parameterName)
+    static String missingMixinForParameter(String componentId, String 
mixinName, String parameterName)
     {
         return MESSAGES
                 .format("missing-mixin-for-parameter", componentId, mixinName, 
parameterName);
@@ -99,5 +99,16 @@
     static String fieldPersistFailure(String componentId, String fieldName, 
Throwable cause)
     {
         return MESSAGES.format("field-persist-failure", componentId, 
fieldName, cause);
+    }
+
+    static String missingRenderVariable(String componentId, String name, 
Collection<String> names)
+    {
+
+        return MESSAGES.format("missing-render-variable", componentId, name, 
InternalUtils.joinSorted(names));
+    }
+
+    static String renderVariableSetWhenNotRendering(String completeId, String 
name)
+    {
+        return MESSAGES.format("render-variable-set-when-not-rendering", 
completeId, name);
     }
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/ClassTransformation.java
 Sat Jan  5 18:05:39 2008
@@ -349,4 +349,12 @@
      *         source line number
      */
     String getMethodIdentifier(TransformMethodSignature signature);
+
+    /**
+     * Returns true if this transformation represents a root class (one that 
extends directly from Object), or
+     * false if this transformation is an extension of another transformed 
class.
+     *
+     * @return true if root class, false is sub-class
+     */
+    boolean isRootTransformation();
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupWriterFactory.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupWriterFactory.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupWriterFactory.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupWriterFactory.java
 Sat Jan  5 18:05:39 2008
@@ -1,17 +1,17 @@
-// Copyright 2006, 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.
-
+// Copyright 2006, 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.ContentType;

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?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
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
 Sat Jan  5 18:05:39 2008
@@ -142,7 +142,7 @@
 
     /**
      * Contributes the factory for serveral built-in binding prefixes 
("asset", "literal", prop",
-     * "block", "component" "message", "validate", "translate").
+     * "block", "component" "message", "validate", "translate", "var").
      */
     public static void contributeBindingSource(MappedConfiguration<String, 
BindingFactory> configuration,
 
@@ -157,12 +157,14 @@
     {
         configuration.add(TapestryConstants.LITERAL_BINDING_PREFIX, new 
LiteralBindingFactory());
         configuration.add(TapestryConstants.PROP_BINDING_PREFIX, 
propBindingFactory);
+
         configuration.add("component", new ComponentBindingFactory());
         configuration.add("message", new MessageBindingFactory());
         configuration.add("validate", new 
ValidateBindingFactory(fieldValidatorSource));
         configuration.add("translate", new 
TranslateBindingFactory(translatorSource));
         configuration.add("block", new BlockBindingFactory());
         configuration.add("asset", new AssetBindingFactory(assetSource));
+        configuration.add("var", new RenderVariableBindingFactory());
     }
 
     public static void 
contributeClasspathAssetAliasManager(MappedConfiguration<String, String> 
configuration,
@@ -211,6 +213,8 @@
      * of the request</li>
      * <li>RenderCommand -- ensures all components also implement [EMAIL 
PROTECTED] RenderCommand}</li>
      * <li>SetupRender, BeginRender, etc. -- correspond to component render 
phases and annotations</li>
+     * <li>InvokePostRenderCleanupOnResources -- makes sure [EMAIL PROTECTED] 
org.apache.tapestry.internal.InternalComponentResources#postRenderCleanup()} is 
invoked
+     * after a component finishes rendering</li>
      * </ul>
      */
     public static void contributeComponentClassTransformWorker(
@@ -283,6 +287,8 @@
         configuration.add("IncludeStylesheet", 
locator.autobuild(IncludeStylesheetWorker.class), "after:SetupRender");
         configuration.add("IncludeJavaScriptLibrary", 
locator.autobuild(IncludeJavaScriptLibraryWorker.class),
                           "after:SetupRender");
+
+        configuration.add("InvokePostRenderCleanupOnResources", new 
InvokePostRenderCleanupOnResourcesWorker());
 
         // This one is always last. Any additional private fields that aren't 
annotated will
         // be converted to clear out at the end of the request.

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.tml?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.tml
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/corelib/pages/ExceptionReport.tml
 Sat Jan  5 18:05:39 2008
@@ -1,60 +1,60 @@
-<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
-  <head>
-    <title>Application Exception</title>
-  </head>
-  <body>
-    <h1 class="t-exception-report">An unexpected application exception has 
occurred.</h1>
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+    <head>
+        <title>Application Exception</title>
+    </head>
+    <body>
+        <h1 class="t-exception-report">An unexpected application exception has 
occurred.</h1>
 
 
-    <div class="t-exception-report">
-      <ul>
-        <t:loop source="stack" value="info">
-          <li>
-            <span class="t-exception-class-name">${info.className}</span>
+        <div class="t-exception-report">
+            <ul>
+                <t:loop source="stack" value="info">
+                    <li>
+                        <span 
class="t-exception-class-name">${info.className}</span>
 
-            <t:if test="info.message">
-              <div class="t-exception-message">${info.message}</div>
-            </t:if>
+                        <t:if test="info.message">
+                            <div 
class="t-exception-message">${info.message}</div>
+                        </t:if>
 
-            <t:if test="showPropertyList">
-              <dl>
-                <t:loop source="info.propertyNames" value="propertyName">
-                  <dt>${propertyName}</dt>
-                  <dd>
-                    <t:renderobject object="propertyValue"/>
-                  </dd>
+                        <t:if test="showPropertyList">
+                            <dl>
+                                <t:loop source="info.propertyNames" 
value="propertyName">
+                                    <dt>${propertyName}</dt>
+                                    <dd>
+                                        <t:renderobject 
object="propertyValue"/>
+                                    </dd>
+                                </t:loop>
+                                <t:if test="info.stackTrace">
+                                    <dt>Stack trace</dt>
+                                    <dd>
+                                        <ul class="t-stack-trace">
+                                            <t:loop source="info.stackTrace" 
value="var:frame">
+                                                <li>${var:frame}</li>
+                                            </t:loop>
+                                        </ul>
+                                    </dd>
+                                </t:if>
+                            </dl>
+                        </t:if>
+                    </li>
                 </t:loop>
-                <t:if test="info.stackTrace">
-                  <dt>Stack trace</dt>
-                  <dd>
-                    <ul class="t-stack-trace">
-                      <t:loop source="info.stackTrace" value="frame">
-                        <li>${frame}</li>
-                      </t:loop>
-                    </ul>
-                  </dd>
-                </t:if>
-              </dl>
-            </t:if>
-          </li>
-        </t:loop>
-      </ul>
-    </div>
-    <div class="t-env-data">
-      <h2>Request</h2>
-      <t:renderobject object="request"/>
+            </ul>
+        </div>
+        <div class="t-env-data">
+            <h2>Request</h2>
+            <t:renderobject object="request"/>
 
-      <t:if test="hasSession">
-        <h2>Session</h2>
-        <dl>
-          <t:loop source="session.attributeNames" value="attributeName">
-            <dt>${attributeName}</dt>
-            <dd>
-              <t:renderobject object="attributeValue"/>
-            </dd>
-          </t:loop>
-        </dl>
-      </t:if>
-    </div>
-  </body>
+            <t:if test="hasSession">
+                <h2>Session</h2>
+                <dl>
+                    <t:loop source="session.attributeNames" 
value="attributeName">
+                        <dt>${attributeName}</dt>
+                        <dd>
+                            <t:renderobject object="attributeValue"/>
+                        </dd>
+                    </t:loop>
+                </dl>
+            </t:if>
+        </div>
+    </body>
 </html>

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/internal/structure/StructureStrings.properties
 Sat Jan  5 18:05:39 2008
@@ -1,4 +1,4 @@
-# Copyright 2006, 2007 The Apache Software Foundation
+# Copyright 2006, 2007, 2008 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.
@@ -12,13 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-missing-parameters=Parameter(s) %s are required for %s, but have not been 
bound.
-no-such-component=Component %s does not contain an embedded component with id 
'%s'.
-get-parameter-failure=Failure reading parameter %s of component %s: %s
-write-parameter-failure=Failure writing parameter %s of component %s: %s
-missing-mixin-for-parameter=Component %s does not contain a mixin named '%s' 
(setting parameter '%s').
-unknown-mixin=Component %s does not contain a mixin of type %s.
-detach-failure=Listener %s failed during page detach: %s
+missing-parameters=Parameter(s) %s are required for %s, but have not been 
bound.
+no-such-component=Component %s does not contain an embedded component with id 
'%s'.
+get-parameter-failure=Failure reading parameter %s of component %s: %s
+write-parameter-failure=Failure writing parameter %s of component %s: %s
+missing-mixin-for-parameter=Component %s does not contain a mixin named '%s' 
(setting parameter '%s').
+unknown-mixin=Component %s does not contain a mixin of type %s.
+detach-failure=Listener %s failed during page detach: %s
 wrong-event-result-type=Return value of method %s is not compatible with the 
expected return type of %s. \
   The value has been ignored. \
   Further lifecycle methods may be invoked, which is likely to cause incorrect 
application behavior. \
@@ -34,3 +34,5 @@
 duplicate-block=Component %s already contains a block with id '%s'. \
   Block ids must be unique (excluding case, which is ignored).
 field-persist-failure=Error persisting field %s:%s: %s
+missing-render-variable=Component %s does not contain a stored render variable 
with name '%s'.  Stored render variables: %s.
+render-variable-set-when-not-rendering=Component %s is not rendering, so 
render variable '%s' may not be updated.

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt 
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/parameters.apt 
Sat Jan  5 18:05:39 2008
@@ -131,11 +131,49 @@
 
*------------+----------------------------------------------------------------------------------+
 | validate   | A <validator specification> used to create some number of field 
validators.      |
 
*------------+----------------------------------------------------------------------------------+
+| var        | Allows a render variable of the component to be read or 
updated. |      |
+*------------+----------------------------------------------------------------------------------+
 
   Parameters have a default prefix, usually "prop:", that is used when the 
prefix is not provided.
   
   A <special prefix>, "inherit:", is used to support {{{#Inherited Parameter 
Bindings}Inherted Parameter Bindings}}.
-    
+
+Render Variables
+
+    Components can have any number of <render variables>.  Render variables 
are named values with no
+    specific type (they are ultimately stored in a Map).  Render variables are 
useful
+    for holding simply values, such as a loop index, that needs to be passed 
from one component to another.
+
+    For example:
+
+---
+  <ul>
+    <li t:type="loop" source="1..10" value="index">${index}</li>
+  </ul>
+
+  private int _index;
+
+  public int getIndex() { return _index; }
+
+  public void setIndex(int index) { _index = index; }
+---
+
+  ... could be rewritten as just:
+
+---
+  <ul>
+    <li t:type="loop" source="1..10" value="var:index">${var:index}</li>
+  </ul>
+---
+
+  In other words, you don't have to define a property in the Java code.  This 
disadvantage is that
+  render variables don't work with the property expression syntax, so you can 
pass around a
+  render variables <value> but you can't reference any of the value's 
properties.
+
+  Render variables are automatically cleared when a component finishes 
rendering.
+
+  Render variable names are case insensitive.
+
 Property Bindings
 
   The "prop:" binding prefix indicates a property binding.

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?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/index.apt Sat Jan  5 
18:05:39 2008
@@ -13,6 +13,13 @@
   Progress on Tapestry 5 is really taking off. This space lists some cool new 
features that have been added
   recently.
 
+  * The new "var:" binding prefix allows for temporary, untyped storage
+    of render-time values without having to define a new component property.
+
+  * Event handler methods may now return a URL, to send a client redirect to 
that URL.
+
+  * Localizations for Italian (it) and Simplified Chinese (zh_CN) have been 
added.
+
   * We're finally starting to see some Ajax support, beginning with the
   
{{{../apidocs/org/apache/tapestry/corelib/mixins/Autocomplete.html}Autocomplete 
mixin}}.
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Start.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Start.tml?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Start.tml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/Start.tml Sat Jan  5 
18:05:39 2008
@@ -307,6 +307,11 @@
             -- Property editor overrides work for the BeanEditor component 
itself (not just the BeanEditForm component)
         </li>
 
+        <li>
+            <t:pagelink page="varbindingdemo">Var Binding Demo</t:pagelink>
+            -- use of the var: binding prefix
+        </li>
+
     </ul>
 
 </html>

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?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
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
 Sat Jan  5 18:05:39 2008
@@ -1327,4 +1327,15 @@
         assertTextPresent("[FirstName Property Editor Override]");
     }
 
+    /**
+     * TAPESTRY-1830
+     */
+    @Test
+    public void var_binding()
+    {
+        start("Var Binding Demo");
+
+        assertTextSeries("//li[%d]", 1, "1", "2", "3");
+    }
+
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/ReturnTypes.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/ReturnTypes.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/ReturnTypes.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/ReturnTypes.java
 Sat Jan  5 18:05:39 2008
@@ -1,17 +1,17 @@
-// Copyright 2007, 2008 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.
-
+// Copyright 2007, 2008 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.ComponentResources;

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/VarBindingDemo.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/VarBindingDemo.java?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/VarBindingDemo.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/VarBindingDemo.java
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,19 @@
+// Copyright 2008 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;
+
+public class VarBindingDemo
+{
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorkerTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorkerTest.java?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorkerTest.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/InvokePostRenderCleanupOnResourcesWorkerTest.java
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,69 @@
+// Copyright 2008 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.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.TransformConstants;
+import org.testng.annotations.Test;
+
+public class InvokePostRenderCleanupOnResourcesWorkerTest extends 
InternalBaseTestCase
+{
+    @Test
+    public void not_a_root_transformation()
+    {
+        ClassTransformation ct = mockClassTransformation();
+        MutableComponentModel model = mockMutableComponentModel();
+
+        train_isRootTransformation(ct, false);
+
+        replay();
+
+        ComponentClassTransformWorker worker = new 
InvokePostRenderCleanupOnResourcesWorker();
+
+        worker.transform(ct, model);
+
+        verify();
+    }
+
+    @Test
+    public void invocation_added_for_root_transformation()
+    {
+        ClassTransformation ct = mockClassTransformation();
+        MutableComponentModel model = mockMutableComponentModel();
+
+        train_isRootTransformation(ct, true);
+
+        train_getResourcesFieldName(ct, "rez");
+
+        train_extendMethod(ct, 
TransformConstants.POST_RENDER_CLEANUP_SIGNATURE, "rez.postRenderCleanup();");
+
+        replay();
+
+        ComponentClassTransformWorker worker = new 
InvokePostRenderCleanupOnResourcesWorker();
+
+        worker.transform(ct, model);
+
+        verify();
+    }
+
+    protected final void train_isRootTransformation(ClassTransformation 
transformation, boolean isRoot)
+    {
+        
expect(transformation.isRootTransformation()).andReturn(isRoot).atLeastOnce();
+    }
+
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImplTest.java
 Sat Jan  5 18:05:39 2008
@@ -15,6 +15,7 @@
 package org.apache.tapestry.internal.structure;
 
 import org.apache.tapestry.Binding;
+import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.internal.InternalComponentResources;
 import org.apache.tapestry.internal.services.Instantiator;
@@ -108,6 +109,143 @@
         resources.bindParameter("fred", binding);
 
         resources.renderInformalParameters(writer);
+
+        verify();
+    }
+
+    @Test
+    public void get_render_variable_exists()
+    {
+        Component component = mockComponent();
+        Instantiator ins = mockInstantiator(component);
+        ComponentModel model = mockComponentModel();
+        ComponentPageElement element = mockComponentPageElement();
+
+        Object value = new Object();
+
+        train_getModel(ins, model);
+
+        train_isRendering(element, true);
+
+        replay();
+
+        ComponentResources resources = new 
InternalComponentResourcesImpl(element, null, ins, null, null, null);
+
+        resources.storeRenderVariable("myRenderVar", value);
+
+        assertSame(resources.getRenderVariable("myrendervar"), value);
+
+        verify();
+    }
+
+    protected final void train_isRendering(ComponentPageElement element, 
boolean isRendering)
+    {
+        expect(element.isRendering()).andReturn(isRendering);
+    }
+
+    @Test
+    public void get_render_variable_missing()
+    {
+        Component component = mockComponent();
+        Instantiator ins = mockInstantiator(component);
+        ComponentModel model = mockComponentModel();
+        ComponentPageElement element = mockComponentPageElement();
+
+        train_getModel(ins, model);
+
+        train_isRendering(element, true);
+        train_isRendering(element, true);
+
+        train_getCompleteId(element, "Foo.bar");
+
+        replay();
+
+        ComponentResources resources = new 
InternalComponentResourcesImpl(element, null, ins, null, null, null);
+
+        resources.storeRenderVariable("fred", "FRED");
+        resources.storeRenderVariable("barney", "BARNEY");
+
+        try
+        {
+            resources.getRenderVariable("wilma");
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(ex.getMessage(),
+                         "Component Foo.bar does not contain a stored render 
variable with name 'wilma'.  Stored render variables: barney, fred.");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void post_render_cleanup_removes_all_variables()
+    {
+        Component component = mockComponent();
+        Instantiator ins = mockInstantiator(component);
+        ComponentModel model = mockComponentModel();
+        ComponentPageElement element = mockComponentPageElement();
+
+        train_getModel(ins, model);
+
+        train_isRendering(element, true);
+        train_isRendering(element, true);
+
+        train_getCompleteId(element, "Foo.bar");
+
+        replay();
+
+        InternalComponentResources resources = new 
InternalComponentResourcesImpl(element, null, ins, null, null, null);
+
+        resources.storeRenderVariable("fred", "FRED");
+        resources.storeRenderVariable("barney", "BARNEY");
+
+        resources.postRenderCleanup();
+
+        try
+        {
+            resources.getRenderVariable("fred");
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(ex.getMessage(),
+                         "Component Foo.bar does not contain a stored render 
variable with name 'fred'.  Stored render variables: (none).");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void store_render_variable_when_not_rendering()
+    {
+        Component component = mockComponent();
+        Instantiator ins = mockInstantiator(component);
+        ComponentModel model = mockComponentModel();
+        ComponentPageElement element = mockComponentPageElement();
+
+        train_getModel(ins, model);
+
+        train_isRendering(element, false);
+
+        train_getCompleteId(element, "Foo.bar");
+
+        replay();
+
+        InternalComponentResources resources = new 
InternalComponentResourcesImpl(element, null, ins, null, null, null);
+
+
+        try
+        {
+            resources.storeRenderVariable("fred", "FRED");
+            unreachable();
+        }
+        catch (IllegalStateException ex)
+        {
+            assertEquals(ex.getMessage(),
+                         "Component Foo.bar is not rendering, so render 
variable 'fred' may not be updated.");
+        }
 
         verify();
     }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app1/pages/VarBindingDemo.tml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app1/pages/VarBindingDemo.tml?rev=609251&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app1/pages/VarBindingDemo.tml
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/integration/app1/pages/VarBindingDemo.tml
 Sat Jan  5 18:05:39 2008
@@ -0,0 +1,18 @@
+<html t:type="Border" 
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd";>
+
+    <h1>var: Binding Prefix Demo</h1>
+
+    <p>var: allows a
+        <em>render variable</em>
+        associated with a component
+        to be read and updated from its embedded components.
+    </p>
+
+    <p>
+        Counting from 1 to 3:
+    </p>
+    <ul>
+        <li t:type="loop" source="1..3" value="var:index">${var:index}</li>
+    </ul>
+
+</html>
\ No newline at end of file

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/InternalUtils.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/InternalUtils.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/InternalUtils.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry/ioc/internal/util/InternalUtils.java
 Sat Jan  5 18:05:39 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -267,9 +267,14 @@
 
     /**
      * Creates a sorted copy of the provided elements, then turns that into a 
comma separated list.
+     *
+     * @return the elements converted to strings, sorted, joined with comma 
... or "(none)" if the elements
+     *         are null or empty
      */
     public static String joinSorted(Collection elements)
     {
+        if (elements == null || elements.isEmpty()) return "(none)";
+
         List<String> list = newList();
 
         for (Object o : elements)

Modified: 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/InternalUtilsTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/InternalUtilsTest.java?rev=609251&r1=609250&r2=609251&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/InternalUtilsTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry/ioc/internal/util/InternalUtilsTest.java
 Sat Jan  5 18:05:39 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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.
@@ -305,5 +305,17 @@
             assertEquals(ex.getMessage(),
                          "Marker annotation class 
org.apache.tapestry.ioc.internal.util.NotRetainedRuntime is not valid because 
it is not visible at runtime. Add a @RetentionPolicy(RUNTIME) to the class.");
         }
+    }
+
+    @Test
+    public void join_sorted_null()
+    {
+        assertEquals(InternalUtils.joinSorted(null), "(none)");
+    }
+
+    @Test
+    public void join_sorted_empty()
+    {
+        assertEquals(InternalUtils.joinSorted(Collections.emptyList()), 
"(none)");
     }
 }


Reply via email to