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 2006/09/26 01:37:29 UTC

svn commit: r449862 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/test/ site/resources/ test/java/org/apache/tapestry/internal/bindings/ test/java/org/apache/ta...

Author: hlship
Date: Mon Sep 25 16:37:28 2006
New Revision: 449862

URL: http://svn.apache.org/viewvc?view=rev&rev=449862
Log:
Speed up the tests by limiting the number of times a "vanilla" Registry is created.

Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/test/BaseRegistryTestCase.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TypeCoercerImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
    tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TypeCoercerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TypeCoercerImpl.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TypeCoercerImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/TypeCoercerImpl.java Mon Sep 25 16:37:28 2006
@@ -76,29 +76,26 @@
             return String.format("CacheKey[%s --> %s]", _sourceClass.getName(), _targetClass
                     .getName());
         }
-
     }
 
     public TypeCoercerImpl(Collection<CoercionTuple> tuples)
     {
         for (CoercionTuple tuple : tuples)
         {
-            Map<Class, List<CoercionTuple>> map = _sourceTypeToTuple;
-
             Class key = tuple.getSourceType();
 
-            addTuple(map, key, tuple);
+            addTuple(key, tuple);
         }
     }
 
-    private void addTuple(Map<Class, List<CoercionTuple>> map, Class key, CoercionTuple tuple)
+    private void addTuple(Class key, CoercionTuple tuple)
     {
-        List<CoercionTuple> list = map.get(key);
+        List<CoercionTuple> list = _sourceTypeToTuple.get(key);
 
         if (list == null)
         {
             list = newList();
-            map.put(key, list);
+            _sourceTypeToTuple.put(key, list);
         }
 
         list.add(tuple);
@@ -110,8 +107,6 @@
     {
         Defense.notNull(targetType, "targetType");
 
-        // TODO: Convert primitive types to wrapper types
-
         // Treat null as void in terms of locating a coercion.
 
         Class sourceType = input != null ? input.getClass() : void.class;
@@ -144,21 +139,23 @@
         Coercion result = _cache.get(key);
 
         if (result == null)
-            result = deduceCoercerAndFillCache(sourceType, targetType);
+            result = findCoercerAndFillCache(sourceType, targetType);
 
         return result;
     }
 
     @Concurrent.Write
-    private Coercion deduceCoercerAndFillCache(Class sourceType, Class targetType)
+    private Coercion findCoercerAndFillCache(Class sourceType, Class targetType)
     {
         // This may locate one of the defined coercions (from the tuples), or may
         // assemble a compound coercision from existing coercisons.
 
         // In a race condition, we may do the work for finding a coercion twice,
-        // and discard the earlier one.
+        // and discard the earlier one. Most likely, however,
+        // different threads will be searching for differnent types of coercion
+        // (different sourceType/targetType combinations).
 
-        Coercion coercer = deduceCoercer(sourceType, targetType);
+        Coercion coercer = findOrCreateCoercer(sourceType, targetType);
 
         _cache.put(new CacheKey(sourceType, targetType), coercer);
 
@@ -175,50 +172,68 @@
      * Here's the real meat; we do a search of the space to find coercions, or a system of
      * coercions, that accomplish the desired coercion.
      * <p>
-     * There's <strong>TREMENDOUS</strong> room to improve this algorithm.
+     * There's <strong>TREMENDOUS</strong> room to improve this algorithm. For example, inheritance
+     * lists could be cached. Further, there's probably more ways to early prune the search.
+     * However, even with dozens or perhaps hundreds of tuples, I suspect the search will still
+     * grind to a conclusion quickly.
      * <p>
      * This does create a good number of short lived temporary objects (the compound tuples), but
      * that's what the GC is really good at.
      * 
      * @param sourceType
      * @param targetType
-     * @return
+     * @return coercer from sourceType to targetType
      */
     @SuppressWarnings("unchecked")
-    private Coercion deduceCoercer(Class sourceType, Class targetType)
+    private Coercion findOrCreateCoercer(Class sourceType, Class targetType)
     {
+        // Since this code is single threaded, these *could* be instance variables,
+        // rather than local variables.
         Set<CoercionTuple> consideredTuples = newSet();
-        LinkedList<CoercionTuple> pool = newLinkedList();
+        LinkedList<CoercionTuple> queue = newLinkedList();
 
-        seedPool(sourceType, consideredTuples, pool);
+        seedQueue(sourceType, consideredTuples, queue);
 
-        while (!pool.isEmpty())
+        while (!queue.isEmpty())
         {
-            CoercionTuple tuple = pool.removeFirst();
+            CoercionTuple tuple = queue.removeFirst();
 
-            // If the tuple results in a value that is assignable to the desired target type.
-            // Later, we may add a concept of "cost" (i.e. number of steps) or "quality"
-            // (how close is the tuple target type to the desired target type). Cost
-            // is currently implicit, as compound tuples are stored deeper in the pool,
+            // If the tuple results in a value type that is assignable to the desired target type,
+            // we're done! Later, we may add a concept of "cost" (i.e. number of steps) or
+            // "quality" (how close is the tuple target type to the desired target type). Cost
+            // is currently implicit, as compound tuples are stored deeper in the queue,
             // so simpler coercions will be located earlier.
 
-            Class tupleTargetClass = tuple.getTargetType();
+            Class tupleTargetType = tuple.getTargetType();
 
-            if (targetType.isAssignableFrom(tupleTargetClass))
+            if (targetType.isAssignableFrom(tupleTargetType))
                 return tuple.getCoercion();
 
             // So .. this tuple doesn't get us directly to the target type.
             // However, it *may* get us part of the way. Each of these
-            // represents a conversion from the source type to an intermediate type.
+            // represents a coercion from the source type to an intermediate type.
             // Now we're going to look for conversions from the intermediate type
             // to some other type.
 
-            addIntermediatesToPool(sourceType, tuple, consideredTuples, pool);
+            queueIntermediates(sourceType, tuple, consideredTuples, queue);
         }
 
         // Not found anywhere. Identify the source and target type and a (sorted) list of
         // all the known coercions.
 
+        throw new IllegalArgumentException(ServicesMessages.noCoercionFound(
+                sourceType,
+                targetType,
+                buildCoercionCatalog()));
+
+    }
+
+    /**
+     * Builds a string listing all the coercions configured for the type coercer, sorted
+     * alphabetically.
+     */
+    private String buildCoercionCatalog()
+    {
         List<String> descriptions = newList();
 
         for (List<CoercionTuple> list : _sourceTypeToTuple.values())
@@ -234,17 +249,15 @@
             }
         }
 
-        throw new IllegalArgumentException(ServicesMessages.noCoercionFound(
-                sourceType,
-                targetType,
-                IOCUtilities.joinSorted(descriptions)));
-
+        return IOCUtilities.joinSorted(descriptions);
     }
 
     /** Seeds the pool with the initial set of coercions for the given type. */
-    private void seedPool(Class sourceType, Set<CoercionTuple> consideredTuples,
-            LinkedList<CoercionTuple> pool)
+    private void seedQueue(Class sourceType, Set<CoercionTuple> consideredTuples,
+            LinkedList<CoercionTuple> queue)
     {
+        // Work from the source type up looking for tuples
+
         for (Class c : new InheritanceSearch(sourceType))
         {
             List<CoercionTuple> tuples = _sourceTypeToTuple.get(c);
@@ -254,15 +267,30 @@
 
             for (CoercionTuple tuple : tuples)
             {
-                pool.addLast(tuple);
+                queue.addLast(tuple);
                 consideredTuples.add(tuple);
             }
         }
     }
 
+    /**
+     * Creates and adds to the pool a new set of coercions based on an intermediate tuple. Adds
+     * compound coercion tuples to the end of the queue.
+     * 
+     * @param sourceType
+     *            the source type of the coercion
+     * @param intermediateTuple
+     *            a tuple that converts from the source type to some intermediate type (that is not
+     *            assignable to the target type)
+     * @param consideredTuples
+     *            set of tuples that have already been added to the pool (directly, or as a compound
+     *            coercion)
+     * @param queue
+     *            the work queue of tuples
+     */
     @SuppressWarnings("unchecked")
-    private void addIntermediatesToPool(Class sourceType, CoercionTuple intermediateTuple,
-            Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> pool)
+    private void queueIntermediates(Class sourceType, CoercionTuple intermediateTuple,
+            Set<CoercionTuple> consideredTuples, LinkedList<CoercionTuple> queue)
     {
         Class intermediateType = intermediateTuple.getTargetType();
 
@@ -280,7 +308,7 @@
 
                 Class newIntermediateType = tuple.getTargetType();
 
-                // If this tuple is for converting from an intermediate type back towards our
+                // If this tuple is for coercing from an intermediate type back towards our
                 // initial source type, then ignore it. This should only be an optimization,
                 // as branches that loop back towards the source type will
                 // eventually be considered and discarded.
@@ -299,9 +327,12 @@
                 CoercionTuple compoundTuple = new CoercionTuple(sourceType, newIntermediateType,
                         compoundCoercer);
 
-                // So, every tuple that goes in can take as input the sourceType
+                // So, every tuple that is added to the queue can take as input the sourceType.
+                // The target type may be another intermdiate type, or may be something
+                // assignable to the target type, which will bring the search to a succesful
+                // conclusion.
 
-                pool.addLast(compoundTuple);
+                queue.addLast(compoundTuple);
                 consideredTuples.add(tuple);
             }
         }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/test/InternalBaseTestCase.java Mon Sep 25 16:37:28 2006
@@ -41,7 +41,11 @@
 import org.apache.tapestry.ioc.def.ServiceDef;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.runtime.RenderQueue;
+import org.apache.tapestry.services.TapestryModule;
 import org.apache.tapestry.test.BaseTestCase;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeSuite;
 
 /**
  * Contains additional factory and training methods related to internal interfaces.
@@ -49,8 +53,53 @@
  * @author Howard M. Lewis Ship
  */
 @SuppressNullCheck
-public class InternalBaseTestCase extends BaseTestCase
+public class InternalBaseTestCase extends BaseTestCase implements Registry
 {
+    private static Registry _registry;
+
+    @BeforeSuite
+    public final void setup_registry()
+    {
+        RegistryBuilder builder = new RegistryBuilder();
+
+        builder.add(TapestryModule.class);
+
+        _registry = builder.build();
+    }
+
+    @AfterSuite
+    public final void shutdown_registry()
+    {
+        _registry.shutdown();
+
+        _registry = null;
+    }
+
+    @AfterMethod
+    public final void cleanupThread()
+    {
+        _registry.cleanupThread();
+    }
+
+    public final <T> T getObject(String reference, Class<T> objectType)
+    {
+        return _registry.getObject(reference, objectType);
+    }
+
+    public final <T> T getService(Class<T> serviceInterface)
+    {
+        return _registry.getService(serviceInterface);
+    }
+
+    public final <T> T getService(String serviceId, Class<T> serviceInterface)
+    {
+        return _registry.getService(serviceId, serviceInterface);
+    }
+
+    public final void shutdown()
+    {
+        throw new UnsupportedOperationException("No registry shutdown until @AfterSuite.");
+    }
 
     protected final InternalComponentResources newInternalComponentResources()
     {

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html Mon Sep 25 16:37:28 2006
@@ -5167,9 +5167,10 @@
 	<div id="contentStash"></div>
 	<div id="storeArea"><div tiddler="DynamicPageState" modifier="HowardLewisShip" modified="200609211635" created="200609211610" tags="">Tapestry 4 has left tracking of dynamic page state as an exercise to the developer.  Mostly, this is done using the ''parameters'' parameter of the ~DirectLink component.\n\nDynamic page state is anything that isn't inside a persistent page property. For the most part, this includes page properties updated by a For component\n\nIt seems likely that this information could be automatically encoded into ~URLs.  \n\nI'm envisioning a service that accumulates a series of //commands//. Each command is used to store a bit of page state. The commands are serializable.  The commands are ultimately serialized into a MIME string and attached as a query parameter to each URL.\n\nWhen such a link is triggered, the commands are de-serialized and each executed in turn. Only when that is finished is any further event processing executed, including calling in
 to to user code.\n\nMy outline for this is to store a series of tuples; each tuple is a component id plus the command to execute.\n\n{{{\npublic interface ComponentCommand&lt;T&gt;\n{\n  void execute(T component);\n}\n}}}\n\nThese commands should be immutable.\n\nSo a component, such as a For loop component, could provide itself and a ComponentCommand instance (probably a static inner class) to some kind of PageStateTracker service.\n\n{{{\npublic interface PageStateTracker\n{\n  void &lt;T&gt; addCommand(T component, ComponentCommand&lt;T&gt; command);\n}\n}}}\n\nThe commands are kept in the order that they are added, except that new commands for the same component //replace// previous commands for that component.\n\nAs with the Tapestry 4 For component, some mechanism will be needed to store object ids inside the URLs (that is, inside the commands serialized into URL query parameters) and translate back to //equivalent// objects when the link is triggered.\n\nDynamic page 
 state outside of a Form will overlap with some of the FormProcessing inside the form.</div>
 <div tiddler="EditTemplate" modifier="HowardLewisShip" modified="200609210649" created="200609210648" tags="">&lt;div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'&gt;&lt;/div&gt;\n&lt;div class='title' macro='view title'&gt;&lt;/div&gt;\n&lt;div class='editor' macro='edit title'&gt;&lt;/div&gt;\n&lt;div class='editor' macro='edit text'&gt;&lt;/div&gt;\n&lt;div class='editor' macro='edit tags'&gt;&lt;/div&gt;&lt;div class='editorFooter'&gt;&lt;span macro='message views.editor.tagPrompt'&gt;&lt;/span&gt;&lt;span macro='tagChooser'&gt;&lt;/span&gt;&lt;/div&gt;</div>
+<div tiddler="EnvironmentalServices" modifier="HowardLewisShip" modified="200609251626" created="200609251547" tags="">Frequently, different components need to //cooperate// during the rendering process.\n\nThis is an established pattern from Tapestry 4, which an enclosing component provides services to the components it encloses. By //encloses// we mean, any components that are rendered as part of the Form's body; give the use of the Block/~RenderBlock components, this can not be determined statically, but is instead determined dynamically, as part of the rendering process.\n\nThe canoncial example of this pattern is Form component, and the complex relationship it has with each form element component it encloses.\n\nIn Tapestry 4, this mechanism was based on the ~IRequestCycle which could store named attributes. The service providing component would store itself into the cycle using a well known name, and service consuming components would retrieve the service using the sam
 e well known name.\n\nFor Tapestry 5, this will be formalized. A new service will be used to manage this information:\n\n{{{\npublic interface Enviroment\n\n  &lt;T&gt; T push(Class&lt;T&gt; type, T instance);\n\n  &lt;T&gt; peek(Class&lt;T&gt; type);\n\n  &lt;T&gt; void pop(Class&lt;T&gt; type);\n}\n}}}\n\n</div>
 <div tiddler="FormProcessing" modifier="HowardLewisShip" modified="200609211540" created="200609210203" tags="forms">Form processing in Tapestry 4 had certain strengths and limitations.\n\nBasically, any action framework that can do a simple mapping from query parameters to bean property names has advantages in terms of simple forms, and Tapestry 4's approach has huge advantages on more complex forms (with some considerable developer and framework overhead).\n\nWith a direct mapping of query parameter names to bean names, each query parameter becomes self describing. You map query parameters to property of some well known bean. You do simple conversions from strings to other types (typically, ints and dates and the like). You drop query parameters that don't match up. You leave a lot of validation and other plumbing (such as getting those values into your DataTransferObjects) to the developer.\n\nBut you never see a ~StaleLinkException.\n\nYou also have some unwanted loophol
 es in your application in that //any// property can be updated through the URL. This is //one step// towards a security hole.\n\n!Tapestry 4 Approach\n\nEvery form component, as it renders, asks the Form that encloses it to provide a client id.  The terminology is a little messed; client id is the unique (within the form) name for //one rendering// of the component. If the component renders multiple times, because of loops, each rendering gets a unique name.  This becomes the &lt;input&gt;'s name attribute, and ultimately, the query parameter name.\n\nTapestry attempts to make the client id match the (user provided) component id. This is not always possible, especially in a loop, in which case a numeric suffix may be appended to the id to (help) ensure uniqueness.\n\nOn render, a sequence of //component activations// occur, guided by the normal render sequence. The exact sequence of activations guides\nthe production of client ids.\n\nUsing more advanced Tapestry techniques,
  including loops, conditionals and the Block/RenderBlock combo, the exact set of components and\ncomponent activations that will occur for a given rendering of a given form can not be predicted statically. Tapestry must actually render out the form\nto discover all of these.\n\nIn fact, while the Form component is producing this series of client ids, it builds up the list and stores it into the rendered page as a hidden form field. It will need it later, when the client-side form is submitted back to the server.\n\nAn advantage of this approach is the disconnect between the query parameter names (the client ids) and the objects and properties being editted. Often the client ids will be //mneumonic// for the properties, but aren't directly mapped to them. Only the components responsible for each query parameter know how to validate the submitted value, and what property of which object will need to be updated.\n\nWhen a form submission occurs, we want to ensure that each quer
 y parameter value read out of the request is applied to the correct property of the correct object. There's a limit to how much Tapestry can help here (because it has only a casual knowledge of this aspect of the application structure).\n\nDuring this submission process, which endded up with the curious name, //rewind phase//, Tapestry must do two things:\n* Activate each component, such that the component may re-determine its client id, read its parameter, and update its page property\n* Validate that the process has not been comprimised by a change of server side state\n\nThat second element is a tricky one; things can go wonky if a race condition occurs between two users. For example, lets take a simple invoice and line item model. If users A and B both read the same invoice, user A adds a line item, and user B changes a line item ... we can have a problem when user B submits the form. Now that there are three line items (not two) in the form, there will be extra componen
 t activations to process query parameters that don't exist in the request. \n\nThis scenario can occur whenever the processing of the form submission is driven by server-side data that can change between request.\n\nTapestry detects this as a difference in the sequence of client ids allocated, and throws a ~StaleLinkException, which is very frustrating for developers to comprehend and fix.\n\nThere are also other edge cases for different race conditions where data is applied to the wrong server-side objects.\n\nThe Tapestry 3 ~ListEdit component, which evolved into the  Tapestry 4 For component, attempts to address this by serializing a series of //object ids// into the form (as a series of hidden fields). This requires a bit of work on the part of the developer to provide an ~IPrimaryKeyConverter that can help convert objects to ids (when rendering) and ids back to objects (during form submission).\n\nGenerally speaking, the Tapestry 4 approach represents layers of kludge o
 n layers of kludge. It works, it gets the job done, it can handle some very complex situations, but it is less than ideal.\n\n!Tapestry 5\n\nThe goal here is to capture the series of //component activations//, along with any significant page state changes, during the render.\n\nThese activations will be a series of //commands//.  For each component activation there will be two commands:  the first command will be used to inform the component of its client id (this command executes during render and during form submission). The second command will request that the client handle the form submission (this command executes only during form submission).\n\nThe serialized series of commands is stored as a hidden form field.\n\nThere's a lot of API to be figured out, especially the relationship between the form components and the form itself.\n\nFurther, a lot of what the Tapestry 4 For component does, in terms of serializing dynamic page state, will need to fold into this as well.
 \n\nThe end result will be a single hidden field with a big MIME string inside it ... but compared to the Tapestry 4 Form component (which has to write out many hidden fields) the whole will be less than the sum of the parts ... due to the overhead of serialization and gzip compression.\n\n\n\n\n\n\n</div>
 <div tiddler="MainMenu" modifier="HowardLewisShip" modified="200609210701" created="200609210643" tags="">MasterIndex\n[[RSS feed|tap5devwiki.xml]]\n\n[[Tapestry 5 Home|http://tapestry.apache.org/tapestry5/]]\n[[Howard's Blog|http://howardlewisship.com/blog/]]\n\n[[Formatting Help|http://www.blogjones.com/TiddlyWikiTutorial.html#EasyToEdit%20Welcome%20NewFeatures%20WhereToFindHelp]]</div>
-<div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200609232249" created="200609202214" tags="">* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* FormProcessing\n* DynamicPageState -- tracking changes to page state during the render</div>
+<div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200609251541" created="200609202214" tags="">* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* FormProcessing\n* DynamicPageState -- tracking changes to page state during the render\n* EnvironmentalServices -- how components cooperate during page render</div>
 <div tiddler="OGNL" modifier="HowardLewisShip" modified="200609202255" created="200609202254" tags="">The [[Object Graph Navigation Library|http://ognl.org]] was an essential part of Tapestry 4.\n\nOGNL is both exceptionally powerful (especially the higher order things it can do, such as list selections and projections). However, for the highest\nend sites, it is also a performance problem, both because of its heavy use of reflection, and because it uses a lot of code inside synchronized blocks.\n\nIt will be optional in Tapestry 5. I believe it will not be part of the tapestry-core, but may be packaged as tapestry-ognl.\n\nThe &quot;prop:&quot; binding prefix is a partial replacement for OGNL in Tapestry 5.  \n\nAs of this writing (Sep 20 2006), the built in support is limited to just simple property names.  At some point in the near future, the PropBindingImprovements will be implemented.</div>
 <div tiddler="PropBinding" modifier="HowardLewisShip" modified="200609232252" created="200609202203" tags="bindings">&quot;prop:&quot; the default in a  lot of cases, i.e., in any Java code.\n\nThis binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be parsed into read-only, invariant bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\n\nThe resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.\n\n!Boolean literals\n\n&quot;true&quot; and &quot;false&quot; should also be converted to in
 variant bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello World'\n}}}\n\n//Remember that the binding expression will always be enclosed in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a component is not immutable, the value of //this// does not ever change,\nand this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis value is always exactly null. This can be used to set a parameter who'se default value is non-null to the explicit value null.\n\n!Property paths\n\nMulti-step property paths are extremely important.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.\n\nThe prop: bin
 ding factory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive.\n\n''Currently, only simple properties, not property paths, are implemented.''\n</div>
 <div tiddler="SideBarTabs" modifier="HowardLewisShip" modified="200609210652" created="200609210651" tags="">&lt;&lt;tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore&gt;&gt;\n</div>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml Mon Sep 25 16:37:28 2006
@@ -6,16 +6,21 @@
 <description>The quick and dirty one-stop shopping of random ideas for Tapestry 5.</description>
 <language>en-us</language>
 <copyright>Copyright 2006 HowardLewisShip</copyright>
-<pubDate>Sat, 23 Sep 2006 22:52:42 GMT</pubDate>
-<lastBuildDate>Sat, 23 Sep 2006 22:52:42 GMT</lastBuildDate>
+<pubDate>Mon, 25 Sep 2006 16:26:08 GMT</pubDate>
+<lastBuildDate>Mon, 25 Sep 2006 16:26:08 GMT</lastBuildDate>
 <docs>http://blogs.law.harvard.edu/tech/rss</docs>
 <generator>TiddlyWiki 2.0.11</generator>
 <item>
-<title>PropBinding</title>
-<description>&quot;prop:&quot; the default in a  lot of cases, i.e., in any Java code.&lt;br /&gt;&lt;br /&gt;This binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.&lt;br /&gt;&lt;br /&gt;The goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.&lt;br /&gt;&lt;br /&gt;!Numeric literals&lt;br /&gt;&lt;br /&gt;Simple numeric literals should be parsed into read-only, invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:5&lt;br /&gt;&lt;br /&gt;prop:-22.7&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.&lt;br /&gt;&lt;br /&gt;!Boolean liter
 als&lt;br /&gt;&lt;br /&gt;&quot;true&quot; and &quot;false&quot; should also be converted to invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:true&lt;br /&gt;&lt;br /&gt;prop:false&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;!String literals&lt;br /&gt;&lt;br /&gt;//Simple// string literals, enclosed in single quotes.  Example:&lt;br /&gt;{{{&lt;br /&gt;prop:'Hello World'&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;//Remember that the binding expression will always be enclosed in double quotes.//&lt;br /&gt;&lt;br /&gt;!This literal&lt;br /&gt;&lt;br /&gt;In some cases, it is useful to be able to identify the current component:&lt;br /&gt;{{{&lt;br /&gt;prop:this&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;Even though a component is not immutable, the value of //this// does not ever change,&lt;br /&gt;and this binding is also invariant.&lt;br /&gt;&lt;br /&gt;!Null literal&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:null&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;This value is always exactly nul
 l. This can be used to set a parameter who'se default value is non-null to the explicit value null.&lt;br /&gt;&lt;br /&gt;!Property paths&lt;br /&gt;&lt;br /&gt;Multi-step property paths are extremely important.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:poll.title&lt;br /&gt;&lt;br /&gt;prop:identity.user.name&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;The initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.&lt;br /&gt;&lt;br /&gt;The prop: binding factory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive.&lt;br /&gt;&lt;br /&gt;''Currently, only simple properties, not property paths, are implemented.''&lt;br /&gt;</description>
-<category>bindings</category>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PropBinding</link>
-<pubDate>Sat, 23 Sep 2006 22:52:29 GMT</pubDate>
+<title>EnvironmentalServices</title>
+<description>Frequently, different components need to //cooperate// during the rendering process.&lt;br /&gt;&lt;br /&gt;This is an established pattern from Tapestry 4, which an enclosing component provides services to the components it encloses. By //encloses// we mean, any components that are rendered as part of the Form's body; give the use of the Block/~RenderBlock components, this can not be determined statically, but is instead determined dynamically, as part of the rendering process.&lt;br /&gt;&lt;br /&gt;The canoncial example of this pattern is Form component, and the complex relationship it has with each form element component it encloses.&lt;br /&gt;&lt;br /&gt;In Tapestry 4, this mechanism was based on the ~IRequestCycle which could store named attributes. The service providing component would store itself into the cycle using a well known name, and service consuming components would retrieve the service using the same well known name.&lt;br /&gt;&lt;br /&gt;For 
 Tapestry 5, this will be formalized. A new service will be used to manage this information:&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;public interface Enviroment&lt;br /&gt;&lt;br /&gt;  &lt;T&gt; T push(Class&lt;T&gt; type, T instance);&lt;br /&gt;&lt;br /&gt;  &lt;T&gt; peek(Class&lt;T&gt; type);&lt;br /&gt;&lt;br /&gt;  &lt;T&gt; void pop(Class&lt;T&gt; type);&lt;br /&gt;}&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#EnvironmentalServices</link>
+<pubDate>Mon, 25 Sep 2006 16:26:08 GMT</pubDate>
+</item>
+<item>
+<title>MasterIndex</title>
+<description>* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix&lt;br /&gt;* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion&lt;br /&gt;* FormProcessing&lt;br /&gt;* DynamicPageState -- tracking changes to page state during the render&lt;br /&gt;* EnvironmentalServices -- how components cooperate during page render</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
+<pubDate>Mon, 25 Sep 2006 15:41:20 GMT</pubDate>
 </item>
 <item>
 <title>TypeCoercion</title>
@@ -23,13 +28,14 @@
 <category>parameters</category>
 <category>types</category>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#TypeCoercion</link>
-<pubDate>Sat, 23 Sep 2006 22:52:19 GMT</pubDate>
+<pubDate>Sat, 23 Sep 2006 22:52:00 GMT</pubDate>
 </item>
 <item>
-<title>MasterIndex</title>
-<description>* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix&lt;br /&gt;* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion&lt;br /&gt;* FormProcessing&lt;br /&gt;* DynamicPageState -- tracking changes to page state during the render</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
-<pubDate>Sat, 23 Sep 2006 22:49:30 GMT</pubDate>
+<title>PropBinding</title>
+<description>&quot;prop:&quot; the default in a  lot of cases, i.e., in any Java code.&lt;br /&gt;&lt;br /&gt;This binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.&lt;br /&gt;&lt;br /&gt;The goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.&lt;br /&gt;&lt;br /&gt;!Numeric literals&lt;br /&gt;&lt;br /&gt;Simple numeric literals should be parsed into read-only, invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:5&lt;br /&gt;&lt;br /&gt;prop:-22.7&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.&lt;br /&gt;&lt;br /&gt;!Boolean liter
 als&lt;br /&gt;&lt;br /&gt;&quot;true&quot; and &quot;false&quot; should also be converted to invariant bindings.&lt;br /&gt;{{{&lt;br /&gt;prop:true&lt;br /&gt;&lt;br /&gt;prop:false&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;!String literals&lt;br /&gt;&lt;br /&gt;//Simple// string literals, enclosed in single quotes.  Example:&lt;br /&gt;{{{&lt;br /&gt;prop:'Hello World'&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;//Remember that the binding expression will always be enclosed in double quotes.//&lt;br /&gt;&lt;br /&gt;!This literal&lt;br /&gt;&lt;br /&gt;In some cases, it is useful to be able to identify the current component:&lt;br /&gt;{{{&lt;br /&gt;prop:this&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;Even though a component is not immutable, the value of //this// does not ever change,&lt;br /&gt;and this binding is also invariant.&lt;br /&gt;&lt;br /&gt;!Null literal&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:null&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;This value is always exactly nul
 l. This can be used to set a parameter who'se default value is non-null to the explicit value null.&lt;br /&gt;&lt;br /&gt;!Property paths&lt;br /&gt;&lt;br /&gt;Multi-step property paths are extremely important.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;prop:poll.title&lt;br /&gt;&lt;br /&gt;prop:identity.user.name&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;The initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.&lt;br /&gt;&lt;br /&gt;The prop: binding factory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive.&lt;br /&gt;&lt;br /&gt;''Currently, only simple properties, not property paths, are implemented.''&lt;br /&gt;</description>
+<category>bindings</category>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PropBinding</link>
+<pubDate>Sat, 23 Sep 2006 22:52:00 GMT</pubDate>
 </item>
 <item>
 <title>DynamicPageState</title>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/bindings/PropBindingFactoryTest.java Mon Sep 25 16:37:28 2006
@@ -23,11 +23,8 @@
 import org.apache.tapestry.internal.ioc.services.ClassFactoryImpl;
 import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.Registry;
-import org.apache.tapestry.ioc.RegistryBuilder;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.services.BindingFactory;
-import org.apache.tapestry.services.TapestryModule;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -247,29 +244,17 @@
         verify();
     }
 
-    private Registry _registry;
-
     private BindingFactory _propFactory;
 
     @BeforeClass
-    public void setupRegistry()
+    public void setup_factory()
     {
-        RegistryBuilder builder = new RegistryBuilder();
-        builder.add(TapestryModule.class);
-
-        _registry = builder.build();
-
-        _propFactory = _registry.getService(
-                "tapestry.internal.PropBindingFactory",
-                BindingFactory.class);
+        _propFactory = getService("tapestry.internal.PropBindingFactory", BindingFactory.class);
     }
 
     @AfterClass
-    public void shutdownRegistry()
+    public void cleanup_factory()
     {
-        _registry.shutdown();
-
-        _registry = null;
         _propFactory = null;
     }
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/DefaultImplementationBuilderImplTest.java Mon Sep 25 16:37:28 2006
@@ -15,7 +15,6 @@
 package org.apache.tapestry.internal.ioc.services;
 
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
-import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.services.DefaultImplementationBuilder;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -26,27 +25,20 @@
  */
 public class DefaultImplementationBuilderImplTest extends InternalBaseTestCase
 {
-    private Registry _registry;
-
     private DefaultImplementationBuilder _builder;
 
     @BeforeClass
     public void setup_builder()
     {
-        _registry = buildRegistry();
-
-        _builder = _registry.getService(
+        _builder = getService(
                 "tapestry.ioc.DefaultImplementationBuilder",
                 DefaultImplementationBuilder.class);
     }
 
     @AfterClass
-    public void shutdown_registry()
+    public void cleanup_builder()
     {
-        _registry.shutdown();
-
         _builder = null;
-        _registry = null;
     }
 
     @Test

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentInstantiatorSourceImplTest.java Mon Sep 25 16:37:28 2006
@@ -249,7 +249,7 @@
         { url }, _contextLoader);
         RegistryBuilder builder = new RegistryBuilder(_extraLoader);
 
-        builder.add(TapestryModule.class, InternalModule.class);
+        builder.add(TapestryModule.class);
 
         _registry = builder.build();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java?view=diff&rev=449862&r1=449861&r2=449862
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/TypeCoercerImplTest.java Mon Sep 25 16:37:28 2006
@@ -3,8 +3,8 @@
 import java.util.Collection;
 
 import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.services.TypeCoercer;
-import org.apache.tapestry.test.BaseRegistryTestCase;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -14,7 +14,7 @@
  * @author Howard M. Lewis Ship
  */
 @SuppressNullCheck
-public class TypeCoercerImplTest extends BaseRegistryTestCase
+public class TypeCoercerImplTest extends InternalBaseTestCase
 {
     private TypeCoercer _coercer;