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 2005/01/30 16:07:52 UTC

cvs commit: jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse InjectState.page TestSpecificationParser.java

hlship      2005/01/30 07:07:52

  Modified:    framework/src/java/org/apache/tapestry/enhance
                        AbstractPropertyWorker.java
                        EnhancementOperation.java
                        EnhancementOperationImpl.java
                        ParameterPropertyWorker.java
               .        status.xml
               src/documentation/content/xdocs/UsersGuide spec.xml
                        common.ent state.xml
               framework/src/test/org/apache/tapestry/enhance
                        TestAbstractPropertyWorker.java
                        TestEnhancementOperation.java
                        TestParameterPropertyWorker.java
               framework/src/java/org/apache/tapestry/spec
                        IComponentSpecification.java SpecFactory.java
                        ComponentSpecification.java
               framework/src/java/org/apache/tapestry/parse
                        SpecificationParser.java Tapestry_3_1.dtd
               framework/src/java/org/apache/tapestry/binding
                        StateBindingFactory.java
                        AbstractBindingFactory.java StateBinding.java
               framework/src/test/org/apache/tapestry/binding
                        TestStateBinding.java
               framework/src/descriptor/META-INF tapestry.enhance.xml
               framework/src/test/org/apache/tapestry/junit/parse
                        TestSpecificationParser.java
  Added:       framework/src/java/org/apache/tapestry/enhance
                        InjectStateWorker.java
               framework/src/test/org/apache/tapestry/enhance
                        TestInjectStateWorker.java
               framework/src/java/org/apache/tapestry/spec
                        InjectStateSpecification.java
                        InjectStateSpecificationImpl.java
               framework/src/test/org/apache/tapestry/junit/parse
                        InjectState.page
  Log:
  Add <inject-state> element to specifications.
  
  Revision  Changes    Path
  1.3       +10 -13    jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/AbstractPropertyWorker.java
  
  Index: AbstractPropertyWorker.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/AbstractPropertyWorker.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- AbstractPropertyWorker.java	5 Jan 2005 23:16:52 -0000	1.2
  +++ AbstractPropertyWorker.java	30 Jan 2005 15:07:51 -0000	1.3
  @@ -17,7 +17,6 @@
   import java.util.Iterator;
   
   import org.apache.hivemind.ErrorLog;
  -import org.apache.hivemind.service.BodyBuilder;
   import org.apache.tapestry.IComponent;
   import org.apache.tapestry.event.PageDetachListener;
   
  @@ -69,22 +68,20 @@
           EnhanceUtils.createSimpleAccessor(op, fieldName, name, propertyType);
           EnhanceUtils.createSimpleMutator(op, fieldName, name, propertyType);
   
  -        BodyBuilder finishLoadBody = op.getBodyBuilderForMethod(
  -                IComponent.class,
  -                EnhanceUtils.FINISH_LOAD_SIGNATURE);
  -
  -        // Inside finish load, "snapshot" the value of the real field
  +        // Copy the real attribute into the default attribute inside finish load
  +        // (allowing a default value to be set inside finishLoad()).
   
  -        finishLoadBody.addln("{0} = {1};", defaultFieldName, fieldName);
  +        op.extendMethodImplementation(
  +                IComponent.class,
  +                EnhanceUtils.FINISH_LOAD_SIGNATURE,
  +                defaultFieldName + " = " + fieldName + ";");
   
  -        // When detaching the page, overwrite the field value with
  -        // the snapshot.
  +        // On page detach, restore the attribute to its default value.
   
  -        BodyBuilder pageDetachedBody = op.getBodyBuilderForMethod(
  +        op.extendMethodImplementation(
                   PageDetachListener.class,
  -                EnhanceUtils.PAGE_DETACHED_SIGNATURE);
  -
  -        pageDetachedBody.addln("{0} = {1};", fieldName, defaultFieldName);
  +                EnhanceUtils.PAGE_DETACHED_SIGNATURE,
  +                fieldName + " = " + defaultFieldName + ";");
   
           // This is not all that necessary, but is proper.
   
  
  
  
  1.8       +15 -13    jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java
  
  Index: EnhancementOperation.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhancementOperation.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- EnhancementOperation.java	5 Jan 2005 23:16:52 -0000	1.7
  +++ EnhancementOperation.java	30 Jan 2005 15:07:51 -0000	1.8
  @@ -16,7 +16,6 @@
   
   import java.util.List;
   
  -import org.apache.hivemind.service.BodyBuilder;
   import org.apache.hivemind.service.MethodSignature;
   import org.apache.tapestry.spec.IComponentSpecification;
   
  @@ -133,19 +132,22 @@
   
       /**
        * Allows for a kind of distributed construction of a particular method, within a particular
  -     * interface. The {@link BodyBuilder}for a given interface method can be obtained and added to.
  -     * When the enhanced class is finialized, the method is added with whatever contents are in its
  -     * body.  If the base class implements the method, then the method body will
  -     * include an initial call to that implementation.
  -     * 
  +     * interface. Code can be appended to the method's implementation throughout the course of the
  +     * enhancement operation. When the enhanced class is finialized, the method is added with
  +     * whatever contents are in its body. If the base class implements the method, then the method
  +     * body will include an initial call to that implementation.
        * <p>
  -     * At this time, this works best for void methods.
  +     * At this time, this works best for void methods (since there isn't an easy way to ensure code
  +     * would be inserted before a final return statement).
        * 
  -     * @param interfaceClass the interface containing the method. If the base class does
  -     *  not implement the interface, then the enhanced class will have the interface
  -     * added.
  -     * @param methodSignature the signature of the method to be added.
  -     * @returns The {@link BodyBuilder} for the specified method.
  +     * @param interfaceClass
  +     *            the interface containing the method. If the base class does not implement the
  +     *            interface, then the enhanced class will have the interface added.
  +     * @param methodSignature
  +     *            the signature of the method to be added.
  +     * @param code
  +     *            the Javassist markup to be added to the body of the method.
        */
  -    public BodyBuilder getBodyBuilderForMethod(Class interfaceClass, MethodSignature methodSignature);
  +    public void extendMethodImplementation(Class interfaceClass, MethodSignature methodSignature,
  +            String code);
   }
  \ No newline at end of file
  
  
  
  1.11      +6 -6      jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java
  
  Index: EnhancementOperationImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/EnhancementOperationImpl.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- EnhancementOperationImpl.java	6 Jan 2005 02:17:21 -0000	1.10
  +++ EnhancementOperationImpl.java	30 Jan 2005 15:07:51 -0000	1.11
  @@ -433,20 +433,20 @@
           return "$" + baseName.substring(dotx + 1) + "_" + _uid++;
       }
   
  -    public BodyBuilder getBodyBuilderForMethod(Class interfaceClass, MethodSignature methodSignature)
  +    public void extendMethodImplementation  (Class interfaceClass, MethodSignature methodSignature, String code)
       {
           addInterfaceIfNeeded(interfaceClass);
   
  -        BodyBuilder result = (BodyBuilder) _incompleteMethods.get(methodSignature);
  +        BodyBuilder builder = (BodyBuilder) _incompleteMethods.get(methodSignature);
   
  -        if (result == null)
  +        if (builder == null)
           {
  -            result = createIncompleteMethod(methodSignature);
  +            builder = createIncompleteMethod(methodSignature);
   
  -            _incompleteMethods.put(methodSignature, result);
  +            _incompleteMethods.put(methodSignature, builder);
           }
   
  -        return result;
  +        builder.addln(code);
       }
   
       private void addInterfaceIfNeeded(Class interfaceClass)
  
  
  
  1.8       +6 -3      jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/ParameterPropertyWorker.java
  
  Index: ParameterPropertyWorker.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/ParameterPropertyWorker.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ParameterPropertyWorker.java	6 Jan 2005 02:17:21 -0000	1.7
  +++ ParameterPropertyWorker.java	30 Jan 2005 15:07:51 -0000	1.8
  @@ -145,9 +145,7 @@
               String propertyName, Class propertyType, String fieldName, String defaultFieldName,
               String cachedFieldName)
       {
  -        BodyBuilder cleanupBody = op.getBodyBuilderForMethod(
  -                IComponent.class,
  -                EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE);
  +        BodyBuilder cleanupBody = new BodyBuilder();
   
           // Cached is only set when the field is updated in the accessor or mutator.
           // After rendering, we want to clear the cached value and cached flag
  @@ -163,6 +161,11 @@
           cleanupBody.addln("{0} = false;", cachedFieldName);
           cleanupBody.addln("{0} = {1};", fieldName, defaultFieldName);
           cleanupBody.end();
  +
  +        op.extendMethodImplementation(
  +                IComponent.class,
  +                EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE,
  +                cleanupBody.toString());
       }
   
       private void addBindingReference(BodyBuilder builder, String localVariableName,
  
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/enhance/InjectStateWorker.java
  
  Index: InjectStateWorker.java
  ===================================================================
  // Copyright 2005 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.enhance;
  
  import java.lang.reflect.Modifier;
  import java.util.Iterator;
  import java.util.List;
  
  import org.apache.hivemind.ErrorLog;
  import org.apache.hivemind.service.BodyBuilder;
  import org.apache.hivemind.service.ClassFabUtils;
  import org.apache.hivemind.service.MethodSignature;
  import org.apache.tapestry.engine.state.ApplicationStateManager;
  import org.apache.tapestry.event.PageDetachListener;
  import org.apache.tapestry.spec.IComponentSpecification;
  import org.apache.tapestry.spec.InjectStateSpecification;
  
  /**
   * Worker for injecting application state objects as properties of the component. These properties
   * are read/write and must be "live" (changes are propogated back into the
   * {@link org.apache.tapestry.engine.state.ApplicationStateManager}). They should also cache in a
   * local variable for efficiency, and clear out that variable at the end of the request.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class InjectStateWorker implements EnhancementWorker
  {
      private ErrorLog _errorLog;
  
      private ApplicationStateManager _applicationStateManager;
  
      public void performEnhancement(EnhancementOperation op)
      {
          IComponentSpecification spec = op.getSpecification();
          List injects = spec.getInjectStateSpecifications();
  
          if (injects.isEmpty())
              return;
  
          // TODO: The EnhancementOperation should have a way of assigning non-conflicting
          // attribute names. What if someone injects a property named "applicationStateManager"
          // as well?
  
          op.addField(
                  "_$applicationStateManager",
                  ApplicationStateManager.class,
                  _applicationStateManager);
  
          Iterator i = injects.iterator();
          while (i.hasNext())
          {
              InjectStateSpecification iss = (InjectStateSpecification) i.next();
  
              try
              {
                  injectState(op, iss.getProperty(), iss.getObjectName());
              }
              catch (Exception ex)
              {
                  _errorLog.error(EnhanceMessages.errorAddingProperty(iss.getProperty(), op
                          .getBaseClass(), ex), iss.getLocation(), ex);
              }
          }
      }
  
      private void injectState(EnhancementOperation op, String propertyName, String objectName)
      {
          Class propertyType =
              EnhanceUtils.extractPropertyType(op, propertyName, null);
          String fieldName = "_$" + propertyName;
  
          op.claimProperty(propertyName);
  
          op.addField(fieldName, propertyType);
  
          BodyBuilder builder = new BodyBuilder();
  
          // Accessor
  
          builder.begin();
          builder.addln("if ({0} == null)", fieldName);
          builder.addln(
                  "  {0} = ({1}) _$applicationStateManager.get(\"{2}\");",
                  fieldName,
                  ClassFabUtils.getJavaClassName(propertyType),
                  objectName);
          builder.addln("return {0};", fieldName);
          builder.end();
  
          String methodName = op.getAccessorMethodName(propertyName);
  
          MethodSignature sig = new MethodSignature(propertyType, methodName, null, null);
  
          op.addMethod(Modifier.PUBLIC, sig, builder.toString());
  
          // Mutator
  
          builder.clear();
          builder.begin();
          builder.addln("_$applicationStateManager.store(\"{0}\", $1);", objectName);
          builder.addln("{0} = $1;", fieldName);
          builder.end();
  
          sig = new MethodSignature(void.class, EnhanceUtils.createMutatorMethodName(propertyName),
                  new Class[]
                  { propertyType }, null);
  
          op.addMethod(Modifier.PUBLIC, sig, builder.toString());
  
          // Extend pageDetached() to clean out the cached field value.
  
          op.extendMethodImplementation(
                  PageDetachListener.class,
                  EnhanceUtils.PAGE_DETACHED_SIGNATURE,
                  fieldName + " = null;");
      }
  
      public void setApplicationStateManager(ApplicationStateManager applicationStateManager)
      {
          _applicationStateManager = applicationStateManager;
      }
  
      public void setErrorLog(ErrorLog errorLog)
      {
          _errorLog = errorLog;
      }
  }
  
  
  1.59      +1 -0      jakarta-tapestry/status.xml
  
  Index: status.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/status.xml,v
  retrieving revision 1.58
  retrieving revision 1.59
  diff -u -r1.58 -r1.59
  --- status.xml	28 Jan 2005 21:07:16 -0000	1.58
  +++ status.xml	30 Jan 2005 15:07:51 -0000	1.59
  @@ -134,6 +134,7 @@
         <action type="update" dev="HLS"> Changed to Form to prevent collisions between query parameters supplied by services (in an ILink) and form element ids. </action>
         <action type="update" dev="HLS"> Change Form (and WML Go) to have the direct and action services injected. </action>
         <action type="update" dev="HLS"> Refactoring to move application state object management out of IEngine and generalize it. </action>
  +      <action type="update" dev="HLS"> Add &lt;inject-state&gt; element to specifications. </action>
       </release>
       <release version="3.0" date="Apr 18 2004">
         <action type="fix" dev="HLS" fixes-bug="28345"> Workbench/Upload exception when no file specified </action>
  
  
  
  1.14      +49 -2     jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/spec.xml
  
  Index: spec.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/spec.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- spec.xml	29 Jan 2005 17:09:18 -0000	1.13
  +++ spec.xml	30 Jan 2005 15:07:51 -0000	1.14
  @@ -137,7 +137,7 @@
       have been consolidated into &lt;set&gt;, which now uses a (wait for it)
       &binding-reference;.</li>
     <li>The 3.1 DTD is more liberal about the order in which elements may be specified than the 3.0 DTD.</li>
  -    
  +  <li>The &spec.inject-state; element has been added.</li>
   </ul>
   
   <p>
  @@ -628,7 +628,7 @@
   <source>
     &spec.description; ?, 
     (&spec.parameter; | &spec.reserved-parameter; | &spec.meta; | &spec.bean; | 
  -   &spec.component; | &spec.asset; | &spec.property; | &spec.inject;)*
  +   &spec.component; | &spec.asset; | &spec.property; | &spec.inject; | &spec.inject-state;)*
   </source>
   
   
  @@ -875,6 +875,53 @@
     
   </section>
   
  +
  +<section id="spec.inject-state">
  +  <title>&lt;inject-state&gt; element</title>
  +  
  +  <p>
  +    Appears in: &spec.component-specification; and &spec.page-specification;.
  +  </p>
  +  
  +  <p>
  +  <em>Injects</em> an &aso; into a component as a property. Reading the property will obtain the state object
  +  from the application state manager (this may cause the object to be created). Updating the property
  +  will store a new value into the application state manager (overwriting the initially created one).
  +  </p>
  +  
  +  <table>
  +<tr>
  +  <th>Name</th>
  +  <th>Type</th>
  +  <th>Required ?</th>
  +  <th>Default Value</th>
  +  <th>Description</th>
  +</tr>
  +
  +<tr>
  +  <td>object</td>
  +  <td>string</td>
  +  <td>yes</td>
  +  <td/>
  +  <td>
  +    The object name of the &aso;    
  +  </td>
  +</tr>
  +
  +<tr>
  +  <td>property</td>
  +  <td>string</td>
  +  <td>yes</td>
  +  <td/>
  +  <td>
  +    The name of the property to be created.  If the class provides an abstract accessor method, then that method defines
  +    the type of the property; otherwise java.lang.Object will be used.
  +  </td>
  +</tr>
  +  </table>
  +  
  +</section>
  +
   <section id="spec.library">
   	<title>&lt;library&gt; element</title>
   	
  
  
  
  1.14      +1 -0      jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/common.ent
  
  Index: common.ent
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/common.ent,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- common.ent	29 Jan 2005 01:03:17 -0000	1.13
  +++ common.ent	30 Jan 2005 15:07:51 -0000	1.14
  @@ -31,6 +31,7 @@
   <!ENTITY spec.description			'<link href="spec.html#spec.description">&lt;description&gt;</link>'>
   <!ENTITY spec.extension				'<link href="spec.html#spec.extension">&lt;extension&gt;</link>'>
   <!ENTITY spec.inject				'<link href="spec.html#spec.inject">&lt;inject&gt;</link>'>
  +<!ENTITY spec.inject-state				'<link href="spec.html#spec.inject-state">&lt;inject-state&gt;</link>'>
   <!ENTITY spec.library				'<link href="spec.html#spec.library">&lt;library&gt;</link>'>
   <!ENTITY spec.library-specification	'<link href="spec.html#spec.library-specification">&lt;library-specification&gt;</link>'>
   <!ENTITY spec.listener-binding		'<link href="spec.html#spec.listener-binding">&lt;listener-binding&gt;</link>'>
  
  
  
  1.10      +35 -4     jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/state.xml
  
  Index: state.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/src/documentation/content/xdocs/UsersGuide/state.xml,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- state.xml	29 Jan 2005 01:03:17 -0000	1.9
  +++ state.xml	30 Jan 2005 15:07:51 -0000	1.10
  @@ -352,7 +352,7 @@
   </note>
   
   <section id="state.aso.defining">
  -  <title>Defining new ASOs</title>
  +  <title>Defining new Application State Objects</title>
     
   <p>
   To create a new ASO, you must update your &hivemind-descriptor; and add a contribution to the
  @@ -380,6 +380,37 @@
     
   </section> <!-- state.aso.defining -->
   
  +<section id="state.aso.access">
  +  <title>Accessing Application State Objects</title>
  +  
  +<p>
  +Tapestry provides an &spec.inject-state; element to support access to the application state objects. This
  +element can be used in any page or component specification to create a new property.  Reading the property
  +will obtain the corresponding state object (which will be created if necessary).  The property may be updated,
  +which will store a new application state object, overwriting the automatically created one.  
  +</p>  
  +
  +<p>
  +For example:
  +</p>
  +
  +<source><![CDATA[
  +<inject-state name="registration" object="registration-data"/>
  +]]></source>
  +
  +<p>
  +This will create a <code>registration</code> property, which can be wired to components.  Your class may define
  +accessors for this property, in which case you should be sure that the application state object is assignable.
  +</p>
  +  
  +<p>
  +The &IPage; interface defines two read-only properties: <code>visit</code> and <code>global</code>. These are both
  +type Object. This is a holdover from Tapestry 3.0, which only supported these two application
  +state objects.
  +</p>
  +  
  +</section>  <!-- state.aso.access -->
  +
     
   </section>  <!-- state.aso -->
   
  @@ -394,7 +425,7 @@
   
   <p>
   This is important and powerful, because an application that runs, even just initially, without
  -a session consumes far less resources that a stateful application.  This is even more important
  +a session consumes far less resources than a stateful application.  This is even more important
   in a clustered environment with multiple servers; any data stored into the HttpSession will
   have to be replicated to other servers in the cluster, which can be expensive in terms of resources (CPU time,
   network bandwidth, and so forth).  Using
  @@ -403,7 +434,7 @@
   </p>
   
   <p>
  -Tapestry defers creation of the HttpSession until one of two things happens:  When a session-scoped ASO is
  +Tapestry defers creation of the HttpSession until one of two things happens:  When a session-scoped &aso; is
   first created, or when the first persistent page property is recorded.  At this point,
   Tapestry will create the HttpSession to hold the object or property.
   </p>
  @@ -418,7 +449,7 @@
   
   <p>
   The <code>state:</code> &binding-reference; combined with the &Conditional; component makes it easy for you to skip
  -portions of a page if a particular ASO does not already exist; this allows you to avoid accidentally force its
  +portions of a page if a particular ASO does not already exist; this allows you to avoid accidentally forcing its
   creation on first reference.
   </p>
   
  
  
  
  1.3       +9 -12     jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestAbstractPropertyWorker.java
  
  Index: TestAbstractPropertyWorker.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestAbstractPropertyWorker.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestAbstractPropertyWorker.java	5 Jan 2005 23:17:27 -0000	1.2
  +++ TestAbstractPropertyWorker.java	30 Jan 2005 15:07:51 -0000	1.3
  @@ -20,7 +20,6 @@
   import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.ErrorLog;
   import org.apache.hivemind.Location;
  -import org.apache.hivemind.service.BodyBuilder;
   import org.apache.hivemind.service.MethodSignature;
   import org.apache.hivemind.test.HiveMindTestCase;
   import org.apache.tapestry.BaseComponent;
  @@ -42,9 +41,6 @@
           MockControl opc = newControl(EnhancementOperation.class);
           EnhancementOperation op = (EnhancementOperation) opc.getMock();
   
  -        BodyBuilder finishLoadBody = new BodyBuilder();
  -        BodyBuilder pageDetachedBody = new BodyBuilder();
  -
           op.findUnclaimedAbstractProperties();
           opc.setReturnValue(Collections.singletonList("fred"));
   
  @@ -65,11 +61,15 @@
           op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[]
           { String.class }, null), "_$fred = $1;");
   
  -        op.getBodyBuilderForMethod(IComponent.class, EnhanceUtils.FINISH_LOAD_SIGNATURE);
  -        opc.setReturnValue(finishLoadBody);
  -
  -        op.getBodyBuilderForMethod(PageDetachListener.class, EnhanceUtils.PAGE_DETACHED_SIGNATURE);
  -        opc.setReturnValue(pageDetachedBody);
  +        op.extendMethodImplementation(
  +                IComponent.class,
  +                EnhanceUtils.FINISH_LOAD_SIGNATURE,
  +                "_$fred$defaultValue = _$fred;");
  +
  +        op.extendMethodImplementation(
  +                PageDetachListener.class,
  +                EnhanceUtils.PAGE_DETACHED_SIGNATURE,
  +                "_$fred = _$fred$defaultValue;");
   
           op.claimProperty("fred");
   
  @@ -77,9 +77,6 @@
   
           new AbstractPropertyWorker().performEnhancement(op);
   
  -        assertEquals("_$fred$defaultValue = _$fred;\n", finishLoadBody.toString());
  -        assertEquals("_$fred = _$fred$defaultValue;\n", pageDetachedBody.toString());
  -
           verifyControls();
       }
   
  
  
  
  1.8       +13 -23    jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestEnhancementOperation.java
  
  Index: TestEnhancementOperation.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestEnhancementOperation.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- TestEnhancementOperation.java	5 Jan 2005 23:17:27 -0000	1.7
  +++ TestEnhancementOperation.java	30 Jan 2005 15:07:51 -0000	1.8
  @@ -23,7 +23,6 @@
   import org.apache.hivemind.ClassResolver;
   import org.apache.hivemind.Location;
   import org.apache.hivemind.impl.DefaultClassResolver;
  -import org.apache.hivemind.service.BodyBuilder;
   import org.apache.hivemind.service.ClassFab;
   import org.apache.hivemind.service.ClassFactory;
   import org.apache.hivemind.service.MethodSignature;
  @@ -511,22 +510,20 @@
   
           MethodSignature sig = EnhanceUtils.PAGE_DETACHED_SIGNATURE;
   
  -        BodyBuilder b = eo.getBodyBuilderForMethod(PageDetachListener.class, sig);
  -
  -        assertEquals("{\n", b.toString());
  +        eo.extendMethodImplementation(PageDetachListener.class, sig, "some-code();");
   
           verifyControls();
   
           replayControls();
   
  -        // Check that repeated calls return the same body builder and do not
  +        // Check that repeated calls do not
           // keep adding methods.
   
  -        assertSame(b, eo.getBodyBuilderForMethod(PageDetachListener.class, sig));
  +        eo.extendMethodImplementation(PageDetachListener.class, sig, "more-code();");
   
           verifyControls();
   
  -        fab.addMethod(Modifier.PUBLIC, sig, "{\n}\n");
  +        fab.addMethod(Modifier.PUBLIC, sig, "{\n  some-code();\n  more-code();\n}\n");
           fabc.setReturnValue(null);
   
           fab.createClass();
  @@ -539,8 +536,6 @@
   
           eo.getConstructor();
   
  -        assertEquals("{\n}\n", b.toString());
  -
           verifyControls();
       }
   
  @@ -562,16 +557,14 @@
   
           MethodSignature sig = EnhanceUtils.FINISH_LOAD_SIGNATURE;
   
  -        BodyBuilder b = eo.getBodyBuilderForMethod(IComponent.class, sig);
  -
  -        assertEquals("{\n  super.finishLoad($$);\n", b.toString());
  +        eo.extendMethodImplementation(IComponent.class, sig, "some-code();");
   
           verifyControls();
   
           cf.newClass("$BaseComponent_97", BaseComponent.class);
           cfc.setReturnValue(fab);
   
  -        fab.addMethod(Modifier.PUBLIC, sig, "{\n  super.finishLoad($$);\n}\n");
  +        fab.addMethod(Modifier.PUBLIC, sig, "{\n  super.finishLoad($$);\n  some-code();\n}\n");
           fabc.setReturnValue(null);
   
           fab.createClass();
  @@ -606,16 +599,17 @@
           // A protected method
           MethodSignature sig = EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE;
   
  -        BodyBuilder b = eo.getBodyBuilderForMethod(IComponent.class, sig);
  -
  -        assertEquals("{\n  super.cleanupAfterRender($$);\n", b.toString());
  +        eo.extendMethodImplementation(IComponent.class, sig, "some-code();");
   
           verifyControls();
   
           cf.newClass("$BaseComponent_97", BaseComponent.class);
           cfc.setReturnValue(fab);
   
  -        fab.addMethod(Modifier.PUBLIC, sig, "{\n  super.cleanupAfterRender($$);\n}\n");
  +        fab.addMethod(
  +                Modifier.PUBLIC,
  +                sig,
  +                "{\n  super.cleanupAfterRender($$);\n  some-code();\n}\n");
           fabc.setReturnValue(null);
   
           fab.createClass();
  @@ -655,16 +649,14 @@
   
           MethodSignature sig = EnhanceUtils.PAGE_DETACHED_SIGNATURE;
   
  -        BodyBuilder b = eo.getBodyBuilderForMethod(PageDetachListener.class, sig);
  -
  -        assertEquals("{\n", b.toString());
  +        eo.extendMethodImplementation(PageDetachListener.class, sig, "some-code();");
   
           verifyControls();
   
           cf.newClass("$ExitingAbstractMethodFixture_97", ExistingAbstractMethodFixture.class);
           cfc.setReturnValue(fab);
   
  -        fab.addMethod(Modifier.PUBLIC, sig, "{\n}\n");
  +        fab.addMethod(Modifier.PUBLIC, sig, "{\n  some-code();\n}\n");
           fabc.setReturnValue(null);
   
           fab.createClass();
  @@ -677,8 +669,6 @@
   
           eo.getConstructor();
   
  -        assertEquals("{\n}\n", b.toString());
  -
           verifyControls();
       }
   }
  \ No newline at end of file
  
  
  
  1.7       +24 -27    jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestParameterPropertyWorker.java
  
  Index: TestParameterPropertyWorker.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestParameterPropertyWorker.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- TestParameterPropertyWorker.java	5 Jan 2005 23:17:27 -0000	1.6
  +++ TestParameterPropertyWorker.java	30 Jan 2005 15:07:51 -0000	1.7
  @@ -186,19 +186,6 @@
           op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[]
           { String.class }, null), builder.toString());
   
  -        BodyBuilder actualCleanup = new BodyBuilder();
  -
  -        op.getBodyBuilderForMethod(IComponent.class, EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE);
  -        opc.setReturnValue(actualCleanup);
  -
  -        replayControls();
  -
  -        ParameterPropertyWorker w = new ParameterPropertyWorker();
  -
  -        w.performEnhancement(op);
  -
  -        verifyControls();
  -
           BodyBuilder expectedCleanup = new BodyBuilder();
   
           expectedCleanup.addln("org.apache.tapestry.IBinding fredBinding = getBinding(\"fred\");");
  @@ -208,7 +195,18 @@
           expectedCleanup.addln("_$fred = _$fred$Default;");
           expectedCleanup.end();
   
  -        assertEquals(expectedCleanup.toString(), actualCleanup.toString());
  +        op.extendMethodImplementation(
  +                IComponent.class,
  +                EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE,
  +                expectedCleanup.toString());
  +
  +        replayControls();
  +
  +        ParameterPropertyWorker w = new ParameterPropertyWorker();
  +
  +        w.performEnhancement(op);
  +
  +        verifyControls();
       }
   
       /**
  @@ -291,10 +289,19 @@
           op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[]
           { String.class }, null), builder.toString());
   
  -        BodyBuilder actualCleanup = new BodyBuilder();
  +        BodyBuilder expectedCleanup = new BodyBuilder();
   
  -        op.getBodyBuilderForMethod(IComponent.class, EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE);
  -        opc.setReturnValue(actualCleanup);
  +        expectedCleanup.addln("org.apache.tapestry.IBinding fredBinding = getBinding(\"barney\");");
  +        expectedCleanup.addln("if (_$fred$Cached && ! fredBinding.isInvariant())");
  +        expectedCleanup.begin();
  +        expectedCleanup.addln("_$fred$Cached = false;");
  +        expectedCleanup.addln("_$fred = _$fred$Default;");
  +        expectedCleanup.end();
  +
  +        op.extendMethodImplementation(
  +                IComponent.class,
  +                EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE,
  +                expectedCleanup.toString());
   
           replayControls();
   
  @@ -304,16 +311,6 @@
   
           verifyControls();
   
  -        BodyBuilder expectedCleanup = new BodyBuilder();
  -
  -        expectedCleanup.addln("org.apache.tapestry.IBinding fredBinding = getBinding(\"barney\");");
  -        expectedCleanup.addln("if (_$fred$Cached && ! fredBinding.isInvariant())");
  -        expectedCleanup.begin();
  -        expectedCleanup.addln("_$fred$Cached = false;");
  -        expectedCleanup.addln("_$fred = _$fred$Default;");
  -        expectedCleanup.end();
  -
  -        assertEquals(expectedCleanup.toString(), actualCleanup.toString());
       }
   
       public void testPrimitiveType()
  
  
  
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/enhance/TestInjectStateWorker.java
  
  Index: TestInjectStateWorker.java
  ===================================================================
  // Copyright 2005 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.enhance;
  
  import java.lang.reflect.Modifier;
  import java.util.Collections;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.hivemind.ApplicationRuntimeException;
  import org.apache.hivemind.ErrorLog;
  import org.apache.hivemind.Location;
  import org.apache.hivemind.service.BodyBuilder;
  import org.apache.hivemind.service.MethodSignature;
  import org.apache.hivemind.test.HiveMindTestCase;
  import org.apache.tapestry.BaseComponent;
  import org.apache.tapestry.engine.state.ApplicationStateManager;
  import org.apache.tapestry.event.PageDetachListener;
  import org.apache.tapestry.spec.IComponentSpecification;
  import org.apache.tapestry.spec.InjectStateSpecification;
  import org.apache.tapestry.spec.InjectStateSpecificationImpl;
  import org.easymock.MockControl;
  
  /**
   * Tests for {@link org.apache.tapestry.enhance.InjectStateWorker}.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class TestInjectStateWorker extends HiveMindTestCase
  {
      private ApplicationStateManager newASM()
      {
          return (ApplicationStateManager) newMock(ApplicationStateManager.class);
      }
  
      private IComponentSpecification newSpecification(List injects)
      {
          MockControl control = newControl(IComponentSpecification.class);
          IComponentSpecification spec = (IComponentSpecification) control.getMock();
  
          spec.getInjectStateSpecifications();
          control.setReturnValue(injects);
  
          return spec;
      }
  
      private List newInjects(String propertyName, String objectName, Location l)
      {
          InjectStateSpecification spec = new InjectStateSpecificationImpl();
  
          spec.setProperty(propertyName);
          spec.setObjectName(objectName);
          spec.setLocation(l);
  
          return Collections.singletonList(spec);
      }
  
      public void testNoWorkToDo()
      {
          IComponentSpecification spec = newSpecification(Collections.EMPTY_LIST);
          MockControl opc = newControl(EnhancementOperation.class);
          EnhancementOperation op = (EnhancementOperation) opc.getMock();
  
          op.getSpecification();
          opc.setReturnValue(spec);
  
          replayControls();
  
          new InjectStateWorker().performEnhancement(op);
  
          verifyControls();
      }
  
      public void testSuccess()
      {
          IComponentSpecification spec = newSpecification(newInjects("fred", "barney", null));
          MockControl opc = newControl(EnhancementOperation.class);
          EnhancementOperation op = (EnhancementOperation) opc.getMock();
  
          op.getSpecification();
          opc.setReturnValue(spec);
  
          ApplicationStateManager asm = newASM();
  
          op.addField("_$applicationStateManager", ApplicationStateManager.class, asm);
  
          op.getPropertyType("fred");
          opc.setReturnValue(Map.class);
  
          op.claimProperty("fred");
          op.addField("_$fred", Map.class);
  
          op.getAccessorMethodName("fred");
          opc.setReturnValue("getFred");
  
          BodyBuilder builder = new BodyBuilder();
  
          // Accessor
  
          builder.begin();
          builder.addln("if (_$fred == null)");
          builder.addln("  _$fred = (java.util.Map) _$applicationStateManager.get(\"barney\");");
          builder.addln("return _$fred;");
          builder.end();
  
          MethodSignature sig = new MethodSignature(Map.class, "getFred", null, null);
  
          op.addMethod(Modifier.PUBLIC, sig, builder.toString());
  
          builder.clear();
          builder.begin();
          builder.addln("_$applicationStateManager.store(\"barney\", $1);");
          builder.addln("_$fred = $1;");
          builder.end();
  
          sig = new MethodSignature(void.class, "setFred", new Class[]
          { Map.class }, null);
  
          op.addMethod(Modifier.PUBLIC, sig, builder.toString());
          op.extendMethodImplementation(
                  PageDetachListener.class,
                  EnhanceUtils.PAGE_DETACHED_SIGNATURE,
                  "_$fred = null;");
  
          replayControls();
  
          InjectStateWorker w = new InjectStateWorker();
          w.setApplicationStateManager(asm);
  
          w.performEnhancement(op);
  
          verifyControls();
      }
  
      public void testFailure()
      {
          Throwable ex = new ApplicationRuntimeException(EnhanceMessages.claimedProperty("fred"));
          Location l = fabricateLocation(22);
  
          IComponentSpecification spec = newSpecification(newInjects("fred", "barney", l));
          MockControl opc = newControl(EnhancementOperation.class);
          EnhancementOperation op = (EnhancementOperation) opc.getMock();
  
          ErrorLog errorLog = (ErrorLog) newMock(ErrorLog.class);
  
          op.getSpecification();
          opc.setReturnValue(spec);
  
          ApplicationStateManager asm = newASM();
  
          op.addField("_$applicationStateManager", ApplicationStateManager.class, asm);
  
          op.getPropertyType("fred");
          opc.setReturnValue(Map.class);
  
          op.claimProperty("fred");
          opc.setThrowable(ex);
  
          op.getBaseClass();
          opc.setReturnValue(BaseComponent.class);
  
          errorLog.error(EnhanceMessages.errorAddingProperty("fred", BaseComponent.class, ex), l, ex);
  
          replayControls();
  
          InjectStateWorker w = new InjectStateWorker();
          w.setApplicationStateManager(asm);
          w.setErrorLog(errorLog);
  
          w.performEnhancement(op);
  
          verifyControls();
      }
  }
  
  
  1.5       +20 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/IComponentSpecification.java
  
  Index: IComponentSpecification.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/IComponentSpecification.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- IComponentSpecification.java	6 Jan 2005 02:17:14 -0000	1.4
  +++ IComponentSpecification.java	30 Jan 2005 15:07:51 -0000	1.5
  @@ -267,4 +267,24 @@
        */
   
       public List getInjectSpecifications();
  +    
  +    /**
  +     * Adds a {@link org.apache.tapestry.spec.InjectStateSpecification}s.
  +     * 
  +     * @since 3.1
  +     */
  +    
  +    public void addInjectStateSpecification(InjectStateSpecification spec);
  +    
  +    /**
  +     * Returns the list of {@link org.apache.tapestry.spec.InjectStateSpecification}s.  Returns
  +     * an empty list if no specifications have been added.
  +     * 
  +     * @since 3.1
  +     * 
  +     */
  +    
  +    public List getInjectStateSpecifications();
  +    
  +    
   }
  \ No newline at end of file
  
  
  
  1.8       +6 -0      jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/SpecFactory.java
  
  Index: SpecFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/SpecFactory.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- SpecFactory.java	29 Jan 2005 01:03:17 -0000	1.7
  +++ SpecFactory.java	30 Jan 2005 15:07:51 -0000	1.8
  @@ -180,4 +180,10 @@
       {
           return new InjectSpecificationImpl();
       }
  +
  +    /** @since 3.1 */
  +    public InjectStateSpecification createInjectStateSpecification()
  +    {
  +        return new InjectStateSpecificationImpl();
  +    }
   }
  \ No newline at end of file
  
  
  
  1.5       +28 -2     jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/ComponentSpecification.java
  
  Index: ComponentSpecification.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/ComponentSpecification.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ComponentSpecification.java	6 Jan 2005 02:17:14 -0000	1.4
  +++ ComponentSpecification.java	30 Jan 2005 15:07:51 -0000	1.5
  @@ -150,6 +150,14 @@
       private List _injectSpecifications;
   
       /**
  +     * List of {@link InjectStateSpecification}.
  +     * 
  +     * @since 3.1
  +     */
  +
  +    private List _injectStateSpecifications;
  +
  +    /**
        * @throws IllegalArgumentException
        *             if the name already exists.
        */
  @@ -583,9 +591,27 @@
   
       public List getInjectSpecifications()
       {
  -        if (_injectSpecifications == null)
  +        return safeList(_injectSpecifications);
  +    }
  +
  +    public void addInjectStateSpecification(InjectStateSpecification spec)
  +    {
  +        if (_injectStateSpecifications == null)
  +            _injectStateSpecifications = new ArrayList();
  +
  +        _injectStateSpecifications.add(spec);
  +    }
  +
  +    public List getInjectStateSpecifications()
  +    {
  +        return safeList(_injectStateSpecifications);
  +    }
  +
  +    private List safeList(List input)
  +    {
  +        if (input == null)
               return Collections.EMPTY_LIST;
   
  -        return Collections.unmodifiableList(_injectSpecifications);
  +        return Collections.unmodifiableList(input);
       }
   }
  \ No newline at end of file
  
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/InjectStateSpecification.java
  
  Index: InjectStateSpecification.java
  ===================================================================
  // Copyright 2005 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.spec;
  
  import org.apache.hivemind.LocationHolder;
  
  /** 
   * Specification element used to describe the injection of an application
   * state object into a component class.
   * 
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public interface InjectStateSpecification extends LocationHolder
  {
      /**
       * Returns the name of the property to create.
       * 
       */
      
      public String getProperty();
      
      public void setProperty(String property);
      
      /**
       * Returns the name of the application state object to be injected.
       * 
       */
      
      public String getObjectName();
      
      public void setObjectName(String objectName);   
  }
  
  
  
  1.1                  jakarta-tapestry/framework/src/java/org/apache/tapestry/spec/InjectStateSpecificationImpl.java
  
  Index: InjectStateSpecificationImpl.java
  ===================================================================
  // Copyright 2005 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.spec;
  
  import org.apache.hivemind.impl.BaseLocatable;
  
  /**
   * @author Howard M. Lewis Ship
   * @since 3.1
   */
  public class InjectStateSpecificationImpl extends BaseLocatable implements InjectStateSpecification
  {
      private String _property;
  
      private String _objectName;
  
      public String getProperty()
      {
          return _property;
      }
  
      public void setProperty(String property)
      {
          _property = property;
      }
  
      public String getObjectName()
      {
          return _objectName;
      }
  
      public void setObjectName(String objectName)
      {
          _objectName = objectName;
      }
  
  }
  
  
  1.18      +23 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/SpecificationParser.java
  
  Index: SpecificationParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/SpecificationParser.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- SpecificationParser.java	29 Jan 2005 17:09:18 -0000	1.17
  +++ SpecificationParser.java	30 Jan 2005 15:07:51 -0000	1.18
  @@ -52,6 +52,7 @@
   import org.apache.tapestry.spec.IParameterSpecification;
   import org.apache.tapestry.spec.IPropertySpecification;
   import org.apache.tapestry.spec.InjectSpecification;
  +import org.apache.tapestry.spec.InjectStateSpecification;
   import org.apache.tapestry.spec.SpecFactory;
   import org.apache.tapestry.util.IPropertyHolder;
   import org.apache.tapestry.util.RegexpMatcher;
  @@ -690,6 +691,12 @@
               enterInject();
               return;
           }
  +        
  +        if (_elementName.equals("inject-state"))
  +        {
  +            enterInjectState();
  +            return;
  +        }
   
           // <asset> is new in 3.1
   
  @@ -1374,6 +1381,22 @@
   
           push(_elementName, spec, STATE_NO_CONTENT);
       }
  +    
  +    private void enterInjectState()
  +    {
  +        String property = getValidatedAttribute("property", PROPERTY_NAME_PATTERN, "invalid-property-name");
  +        String objectName = getAttribute("object");
  +
  +        InjectStateSpecification spec = _factory.createInjectStateSpecification();
  +
  +        spec.setProperty(property);
  +        spec.setObjectName(objectName);
  +        IComponentSpecification cs = (IComponentSpecification) peekObject();
  +
  +        cs.addInjectStateSpecification(spec);
  +
  +        push(_elementName, spec, STATE_NO_CONTENT);
  +    }    
   
       private void enterReservedParameter()
       {
  
  
  
  1.10      +20 -2     jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/Tapestry_3_1.dtd
  
  Index: Tapestry_3_1.dtd
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/parse/Tapestry_3_1.dtd,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- Tapestry_3_1.dtd	29 Jan 2005 17:09:18 -0000	1.9
  +++ Tapestry_3_1.dtd	30 Jan 2005 15:07:51 -0000	1.10
  @@ -38,6 +38,7 @@
   - Consoliated <context-asset>, <private-asset> and <external-asset> into <asset>
   - Consolidated <set-property> and <set-message-property> into <set>
   - More flexibility on the order of elements
  +- Added <inject-state>
   -->
   <!-- =======================================================
   Entity: attribute-flag
  @@ -218,7 +219,7 @@
     allow-informal-parameters:  If yes (the default), informal parameters (parameters that are not
       explictily defined) are allowed.
   -->
  -<!ELEMENT component-specification (description?, (parameter | reserved-parameter | meta | bean | component | asset | property | inject)*)>
  +<!ELEMENT component-specification (description?, (parameter | reserved-parameter | meta | bean | component | asset | property | inject | inject-state)*)>
   <!ATTLIST component-specification
   	class CDATA #IMPLIED
   	allow-body %attribute-flag; "yes"
  @@ -270,7 +271,24 @@
     property CDATA #REQUIRED
     object CDATA #REQUIRED
   >
  +<!-- =======================================================
  +Element: inject-state
  +Contained by: component-specification, page-specification
  +
  +Defines a new property mapped to an application state object.
  +Reading the property will return the current value of the state
  +object, and updating the property will change the value of the state
  +object.
   
  +Attributes:
  +  property The name of the property.
  +  object: The name of the application state object.
  +-->
  +<!ELEMENT inject-state EMPTY>
  +<!ATTLIST inject-state
  +  property CDATA #REQUIRED
  +  object CDATA #REQUIRED
  +>
   <!-- =======================================================
   Element: library
   Appears in: application-specification, library-specification
  @@ -369,7 +387,7 @@
   Attributes:
     class: The Java class to instantiate for the component.
   -->
  -<!ELEMENT page-specification (description?,  (meta| bean | component | asset | property | inject)*)>
  +<!ELEMENT page-specification (description?,  (meta| bean | component | asset | property | inject | inject-state)*)>
   <!ATTLIST page-specification
   	class CDATA #IMPLIED
   >
  
  
  
  1.2       +14 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/StateBindingFactory.java
  
  Index: StateBindingFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/StateBindingFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- StateBindingFactory.java	29 Jan 2005 01:03:16 -0000	1.1
  +++ StateBindingFactory.java	30 Jan 2005 15:07:51 -0000	1.2
  @@ -1,3 +1,17 @@
  +// Copyright 2005 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.binding;
   
   import org.apache.hivemind.Location;
  
  
  
  1.2       +14 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/AbstractBindingFactory.java
  
  Index: AbstractBindingFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/AbstractBindingFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractBindingFactory.java	29 Jan 2005 01:03:16 -0000	1.1
  +++ AbstractBindingFactory.java	30 Jan 2005 15:07:51 -0000	1.2
  @@ -1,3 +1,17 @@
  +// Copyright 2005 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.binding;
   
   import org.apache.tapestry.coerce.ValueConverter;
  
  
  
  1.2       +14 -0     jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/StateBinding.java
  
  Index: StateBinding.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/java/org/apache/tapestry/binding/StateBinding.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- StateBinding.java	29 Jan 2005 01:03:16 -0000	1.1
  +++ StateBinding.java	30 Jan 2005 15:07:51 -0000	1.2
  @@ -1,3 +1,17 @@
  +// Copyright 2005 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.binding;
   
   import org.apache.hivemind.ApplicationRuntimeException;
  
  
  
  1.2       +14 -0     jakarta-tapestry/framework/src/test/org/apache/tapestry/binding/TestStateBinding.java
  
  Index: TestStateBinding.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/binding/TestStateBinding.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestStateBinding.java	29 Jan 2005 01:03:17 -0000	1.1
  +++ TestStateBinding.java	30 Jan 2005 15:07:52 -0000	1.2
  @@ -1,3 +1,17 @@
  +// Copyright 2005 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.binding;
   
   import org.apache.hivemind.ApplicationRuntimeException;
  
  
  
  1.7       +13 -0     jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.enhance.xml
  
  Index: tapestry.enhance.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/descriptor/META-INF/tapestry.enhance.xml,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- tapestry.enhance.xml	27 Jan 2005 20:27:58 -0000	1.6
  +++ tapestry.enhance.xml	30 Jan 2005 15:07:52 -0000	1.7
  @@ -69,6 +69,7 @@
       <command id="specified-property" object="service:SpecifiedPropertyWorker" before="abstract-property"/>
       <command id="parameter" object="service:ParameterPropertyWorker" before="abstract-property"/>
       <command id="inject" object="service:InjectWorker" before="abstract-property"/>
  +    <command id="inject-state" object="service:InjectStateWorker" before="abstract-property"/>
       
       <!-- This should be second to last, or at least, after all other workers have 
            added and claimed any properties they are going to. -->
  @@ -112,6 +113,18 @@
       
     </service-point>
     
  +  <service-point id="InjectStateWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
  +    
  +    Injects properties that reference application state objects.
  +    
  +    <invoke-factory>
  +      <construct class="org.apache.tapestry.enhance.InjectStateWorker">
  +        <set-service property="applicationStateManager" service-id="tapestry.state.ApplicationStateManager"/>
  +      </construct>
  +    </invoke-factory>
  +    
  +  </service-point>
  +  
     <service-point id="AbstractPropertyWorker" interface="org.apache.tapestry.enhance.EnhancementWorker">
       
       Finds otherwise unclaimed abstract properties and converts them into concrete properties, as if
  
  
  
  1.10      +17 -0     jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/TestSpecificationParser.java
  
  Index: TestSpecificationParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/TestSpecificationParser.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- TestSpecificationParser.java	29 Jan 2005 17:09:18 -0000	1.9
  +++ TestSpecificationParser.java	30 Jan 2005 15:07:52 -0000	1.10
  @@ -33,6 +33,7 @@
   import org.apache.tapestry.spec.IParameterSpecification;
   import org.apache.tapestry.spec.IPropertySpecification;
   import org.apache.tapestry.spec.InjectSpecification;
  +import org.apache.tapestry.spec.InjectStateSpecification;
   import org.apache.tapestry.spec.ListenerBindingSpecification;
   import org.apache.tapestry.util.xml.DocumentParseException;
   
  @@ -1034,4 +1035,20 @@
   
           assertEquals("path/to/asset", as.getPath());
       }
  +    
  +    /** @since 3.1 */
  +    
  +    public void testInjectState() throws Exception
  +    {
  +        IComponentSpecification cs = parsePage("InjectState.page");
  +        
  +        List l = cs.getInjectStateSpecifications();
  +        
  +        assertEquals(1,l.size());
  +        
  +        InjectStateSpecification s = (InjectStateSpecification)l.get(0);
  +        
  +        assertEquals("fred", s.getProperty());
  +        assertEquals("barney", s.getObjectName());
  +    }
   }
  \ No newline at end of file
  
  
  
  1.1                  jakarta-tapestry/framework/src/test/org/apache/tapestry/junit/parse/InjectState.page
  
  Index: InjectState.page
  ===================================================================
  <?xml version="1.0"?>
  <!-- 
     Copyright 2005 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.
  -->
  
  <!DOCTYPE page-specification PUBLIC 
    "-//Apache Software Foundation//Tapestry Specification 3.1//EN" 
    "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_1.dtd">
  <page-specification>
      <inject-state property="fred" object="barney"/>
  </page-specification>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org