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 2003/01/24 01:49:39 UTC

cvs commit: jakarta-tapestry/framework/src/net/sf/tapestry/util package.html

hlship      2003/01/23 16:49:39

  Modified:    config   common.properties log4j.properties
               framework/src/net/sf/tapestry/valid package.html
               framework/src/net/sf/tapestry/pageload PageLoader.java
                        package.html
               examples/Tutorial build.xml
               framework/src/net/sf/tapestry/link ExternalLink.java
                        PageLink.java DirectLink.java ActionLink.java
                        package.html
               junit/src/net/sf/tapestry/junit/mock TestExternal.xml
                        TestPersistentProperties.xml TestSimple.xml
                        TestLibrary.xml MockTestCase.java MockTester.java
               framework/src/net/sf/tapestry/binding package.html
               framework/src/net/sf/tapestry/param package.html
               .        .classpath Readme.html build.xml TODO.html
               examples/Vlib build.xml
               junit    build.xml
               framework/src/net/sf/tapestry/engine ResetService.java
                        HomeService.java AbstractService.java
                        ActionService.java AbstractEngine.java
                        RestartService.java PageService.java
                        DirectService.java package.html
                        ExternalService.java
               contrib/src/net/sf/tapestry/contrib/valid package.html
               doc/src/UsersGuide TapestryUsersGuide.xml spec.xml state.xml
               framework/src/net/sf/tapestry Gesture.java
                        TapestryStrings.properties IEngine.java
                        Tapestry.java IEngineService.java AbstractPage.java
                        package.html
               contrib/src/net/sf/tapestry/contrib/ejb package.html
               framework/src/net/sf/tapestry/spec SpecFactory.java
                        ComponentSpecification.java package.html
               framework/src/net/sf/tapestry/util/io package.html
               framework/src/net/sf/tapestry/parse Tapestry_1_4.dtd
                        SpecificationParser.java package.html
               framework/src/net/sf/tapestry/script package.html
               framework/src/net/sf/tapestry/html package.html Frame.java
                        Shell.java
               framework/src/net/sf/tapestry/util/exception package.html
               examples/Vlib/context/WEB-INF Border.html
               framework/src/net/sf/tapestry/asset PrivateAsset.java
                        package.html AssetService.java
               contrib/src/net/sf/tapestry/contrib/jdbc package.html
               framework/src/net/sf/tapestry/util/prop OgnlUtils.java
                        package.html
               framework/src/net/sf/tapestry/record package.html
               junit/src/net/sf/tapestry/junit/parse
                        SpecificationParserTest.java
               examples/Tutorial/context/WEB-INF/workbench Border.html
               framework/src/net/sf/tapestry/wml package.html
               examples/wap build.xml
               examples/Vlib/context ApplicationUnavailable.html
               framework/src/net/sf/tapestry/pages package.html
               junit/src/net/sf/tapestry/junit TapestrySuite.java
                        MockEngine.java BindingsTestCase.java
               framework/src/net/sf/tapestry/event package.html
               framework build.xml
               framework/src/net/sf/tapestry/bean package.html
               framework/src/net/sf/tapestry/util/pool package.html
               contrib/src/net/sf/tapestry/contrib/inspector
                        ShowTemplate.java package.html InspectorButton.java
               framework/src/net/sf/tapestry/form Form.java package.html
               eclipse  Tapestry-Mock.launch Tapestry-Junit.launch
               web      new.html
               framework/src/net/sf/tapestry/callback package.html
               doc/src/ContributorsGuide ContributorsGuide.xml
               framework/src/net/sf/tapestry/components package.html
               examples/Tutorial/context redirect-target.html
               framework/src/net/sf/tapestry/listener package.html
               framework/src/net/sf/tapestry/util/xml package.html
               framework/src/net/sf/tapestry/util package.html
  Added:       junit/Context9 Six.html Three.html Four.html Home.html
                        Two.html Five.html README Seven.html
               framework/src/net/sf/tapestry/pageload
                        PropertyInitializer.java
               junit/src/net/sf/tapestry/junit/mock
                        TestPropertySpecification.xml
               junit/Context9/WEB-INF Five.page Two.page Home.page
                        Four.page Six.page Seven.page Three.page
               framework/src/net/sf/tapestry IComponentClassEnhancer.java
               framework/src/net/sf/tapestry/spec
                        PropertySpecification.java
               junit/src/net/sf/tapestry/junit/mock/c9 Four.java Five.java
                        Seven.java Three.java Six.java
               lib/ext  bcel-5.0.jar
               junit/src/net/sf/tapestry/junit/enhance
                        TestClassFabricator.java
               junit/context8 README
               framework/src/net/sf/tapestry/enhance
                        EnhanceClassLoader.java package.html
                        ClassFabricator.java MethodFabricator.java
                        DefaultComponentClassEnhancer.java
               junit/src/net/sf/tapestry/junit/parse
                        DuplicatePropertySpecification.page
                        PropertySpecifications.page
  Log:
  Add support for declarative transient and persistent properties.
  
  Revision  Changes    Path
  1.17      +6 -5      jakarta-tapestry/config/common.properties
  
  Index: common.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/config/common.properties,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- common.properties	20 Jan 2003 21:18:03 -0000	1.16
  +++ common.properties	24 Jan 2003 00:49:31 -0000	1.17
  @@ -28,15 +28,16 @@
   
   # Versions of various external libs
   
  +bcel.jar=bcel-5.0.jar
  +bsf.jar=bsf-2.3.0.jar
  +commons-logging.jar=commons-logging-1.0.2.jar
  +commons-lang.jar=commons-lang-1.0.jar
   jakarta-oro.jar=jakarta-oro-2.0.6.jar
   jcommon.jar=jcommon-0.6.4.jar
  +jetty.jar=org.mortbay.jetty-jdk1.2.jar
   jfreechart.jar=jfreechart-0.9.2.jar
   log4j.jar=log4j-1.2.6.jar
   ognl.jar=ognl-2.3.0-opt.jar
  -jetty.jar=org.mortbay.jetty-jdk1.2.jar
  -commons-logging.jar=commons-logging-1.0.2.jar
  -commons-lang.jar=commons-lang-1.0.jar
  -bsf.jar=bsf-2.3.0.jar
   
   # Used as part of copyrights
   
  
  
  
  1.3       +4 -2      jakarta-tapestry/config/log4j.properties
  
  Index: log4j.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/config/log4j.properties,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- log4j.properties	28 Aug 2002 21:21:00 -0000	1.2
  +++ log4j.properties	24 Jan 2003 00:49:31 -0000	1.3
  @@ -7,4 +7,6 @@
   
   # A1 uses PatternLayout.
   log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  -log4j.appender.A1.layout.ConversionPattern=%c{1} [%p] %m%n
  +log4j.appender.A1.layout.ConversionPattern=%r %c{1} [%p] %m%n
  +
  +log4j.category.net.sf.tapestry.enhance=debug
  \ No newline at end of file
  
  
  
  1.6       +1 -1      jakarta-tapestry/framework/src/net/sf/tapestry/valid/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/valid/package.html,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- package.html	3 May 2002 18:12:57 -0000	1.5
  +++ package.html	24 Jan 2003 00:49:31 -0000	1.6
  @@ -17,7 +17,7 @@
   <p>Fields can also have a {@link net.sf.tapestry.valid.FieldLabel} that reflects the state (normal or error)
   of the field.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/junit/Context9/Six.html
  
  Index: Six.html
  ===================================================================
  <html jwcid="@Shell" title="Six">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ value ]]">22</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ value ]]">33</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ value ]]">44</span>]
  
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/Three.html
  
  Index: Three.html
  ===================================================================
  <html jwcid="@Shell" title="Three">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ word ]]">some word</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ word ]]">word from list</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ word ]]">last word in list</span>]
  
  <p>
  Page class: [<span jwcid="@Insert" value="[[ page.getClass().getName() ]]">foo.Bar</span>]
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/Four.html
  
  Index: Four.html
  ===================================================================
  <html jwcid="@Shell" title="Four">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ word ]]">some word</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ word ]]">word from list</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ word ]]">last word in list</span>]
  
  <p>
  Page class: [<span jwcid="@Insert" value="[[ page.getClass().getName() ]]">foo.Bar</span>]
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/Home.html
  
  Index: Home.html
  ===================================================================
  <html jwcid="@Shell" title="Home">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ word ]]">some word</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ word ]]">word from list</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ word ]]">last word in list</span>]
  
  <p>
  Page class: [<span jwcid="@Insert" value="[[ page.getClass().getName() ]]">foo.Bar</span>]
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/Two.html
  
  Index: Two.html
  ===================================================================
  <html jwcid="@Shell" title="Two">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ number ]]">22</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ number ]]">33</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ number ]]">44</span>]
  
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/Five.html
  
  Index: Five.html
  ===================================================================
  <html jwcid="@Shell" title="Five">
  <body jwcid="@Body">
  
  Initial value: [<span jwcid="@Insert" value="[[ word ]]">some word</span>]
  
  <p>
  <ul>
  <li jwcid="loop"><span jwcid="@Insert" value="[[ word ]]">word from list</span></li>
  </ul>
  
  
  <p>
  Final value: [<span jwcid="@Insert" value="[[ word ]]">last word in list</span>]
  
  <p>
  Page class: [<span jwcid="@Insert" value="[[ page.getClass().getName() ]]">foo.Bar</span>]
  </body>
  </html>
  
  
  1.1                  jakarta-tapestry/junit/Context9/README
  
  Index: README
  ===================================================================
  This context contains examples that test the <property-specification> element in pages and components.
  
  
  
  
  1.1                  jakarta-tapestry/junit/Context9/Seven.html
  
  Index: Seven.html
  ===================================================================
  <html jwcid="@Shell" title="Seven">
  <body jwcid="@Body">
  
  Boolean value: [<span jwcid="@Insert" value="[[ booleanValue ]]"/>]
  <br>
  Byte value: [<span jwcid="@Insert" value="[[ byteValue ]]"/>]
  <br>
  Char value: [<span jwcid="@Insert" value="[[ charValue ]]"/>]
  <br>
  Short value: [<span jwcid="@Insert" value="[[ shortValue ]]"/>]
  <br>
  Int value: [<span jwcid="@Insert" value="[[ intValue ]]"/>]
  <br>
  Long value: [<span jwcid="@Insert" value="[[ longValue ]]"/>]
  <br>
  Float value: [<span jwcid="@Insert" value="[[ floatValue ]]"/>]
  <br>
  Double  value: [<span jwcid="@Insert" value="[[ doubleValue ]]"/>]
  <br>
  String value: [<span jwcid="@Insert" value="[[ stringValue ]]"/>]
  
  <p>
  <a href="#" jwcid="@DirectLink" listener="[[ listeners.update ]]">change values</a>
  
  </body>
  </html>
  
  
  1.18      +179 -61   jakarta-tapestry/framework/src/net/sf/tapestry/pageload/PageLoader.java
  
  Index: PageLoader.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/pageload/PageLoader.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- PageLoader.java	17 Jan 2003 17:40:16 -0000	1.17
  +++ PageLoader.java	24 Jan 2003 00:49:31 -0000	1.18
  @@ -64,14 +64,12 @@
   
   import javax.servlet.http.HttpServletRequest;
   
  -import org.apache.commons.logging.Log;
  -import org.apache.commons.logging.LogFactory;
  -
   import net.sf.tapestry.ApplicationRuntimeException;
   import net.sf.tapestry.BaseComponent;
   import net.sf.tapestry.IAsset;
   import net.sf.tapestry.IBinding;
   import net.sf.tapestry.IComponent;
  +import net.sf.tapestry.IComponentClassEnhancer;
   import net.sf.tapestry.IEngine;
   import net.sf.tapestry.INamespace;
   import net.sf.tapestry.IPage;
  @@ -88,6 +86,7 @@
   import net.sf.tapestry.binding.ExpressionBinding;
   import net.sf.tapestry.binding.ListenerBinding;
   import net.sf.tapestry.binding.StringBinding;
  +import net.sf.tapestry.event.PageDetachListener;
   import net.sf.tapestry.html.BasePage;
   import net.sf.tapestry.resolver.ComponentSpecificationResolver;
   import net.sf.tapestry.resource.ContextResourceLocation;
  @@ -99,6 +98,11 @@
   import net.sf.tapestry.spec.ContainedComponent;
   import net.sf.tapestry.spec.ListenerBindingSpecification;
   import net.sf.tapestry.spec.ParameterSpecification;
  +import net.sf.tapestry.spec.PropertySpecification;
  +import net.sf.tapestry.util.prop.OgnlUtils;
  +
  +import org.apache.commons.logging.Log;
  +import org.apache.commons.logging.LogFactory;
   
   /**
    *  Runs the process of building the component hierarchy for an entire page.
  @@ -119,6 +123,7 @@
   
       private IEngine _engine;
       private IResourceResolver _resolver;
  +    private IComponentClassEnhancer _enhancer;
       private ISpecificationSource _specificationSource;
       private IPageSource _pageSource;
       private ComponentSpecificationResolver _componentResolver;
  @@ -167,7 +172,10 @@
           private String _containerParameterName;
           private String _parameterName;
   
  -        private QueuedInheritedBinding(IComponent component, String containerParameterName, String parameterName)
  +        private QueuedInheritedBinding(
  +            IComponent component,
  +            String containerParameterName,
  +            String parameterName)
           {
               _component = component;
               _containerParameterName = containerParameterName;
  @@ -198,6 +206,7 @@
   
           _specificationSource = engine.getSpecificationSource();
           _resolver = engine.getResourceResolver();
  +        _enhancer = engine.getComponentClassEnhancer();
           _componentResolver = new ComponentSpecificationResolver(cycle);
   
           RequestContext context = cycle.getRequestContext();
  @@ -209,7 +218,8 @@
   
           String servletPath = request.getServletPath();
   
  -        _servletLocation = new ContextResourceLocation(context.getServlet().getServletContext(), servletPath);
  +        _servletLocation =
  +            new ContextResourceLocation(context.getServlet().getServletContext(), servletPath);
       }
   
       /**
  @@ -229,7 +239,11 @@
        *
        **/
   
  -    private void bind(IComponent container, IComponent component, ContainedComponent contained, Map propertyBindings)
  +    private void bind(
  +        IComponent container,
  +        IComponent component,
  +        ContainedComponent contained,
  +        Map propertyBindings)
           throws PageLoaderException
       {
           ComponentSpecification spec = component.getSpecification();
  @@ -248,7 +262,10 @@
   
               if (formalOnly && !isFormal)
                   throw new PageLoaderException(
  -                    Tapestry.getString("PageLoader.formal-parameters-only", component.getExtendedId(), name),
  +                    Tapestry.getString(
  +                        "PageLoader.formal-parameters-only",
  +                        component.getExtendedId(),
  +                        name),
                       component,
                       null);
   
  @@ -276,7 +293,8 @@
   
               if (type == BindingType.INHERITED)
               {
  -                QueuedInheritedBinding queued = new QueuedInheritedBinding(component, bspec.getValue(), name);
  +                QueuedInheritedBinding queued =
  +                    new QueuedInheritedBinding(component, bspec.getValue(), name);
                   _inheritedBindingQueue.add(queued);
                   continue;
               }
  @@ -317,7 +335,10 @@
   
               if (parameterSpec.isRequired() && component.getBinding(name) == null)
                   throw new PageLoaderException(
  -                    Tapestry.getString("PageLoader.required-parameter-not-bound", name, component.getExtendedId()),
  +                    Tapestry.getString(
  +                        "PageLoader.required-parameter-not-bound",
  +                        name,
  +                        component.getExtendedId()),
                       component,
                       null);
           }
  @@ -337,7 +358,11 @@
           }
       }
   
  -    private IBinding convert(BindingType type, String bindingValue, IComponent container, Map propertyBindings)
  +    private IBinding convert(
  +        BindingType type,
  +        String bindingValue,
  +        IComponent container,
  +        Map propertyBindings)
       {
           // The most common type.  propertyBindings is a cache of
           // property bindings for the container, we re-use
  @@ -387,19 +412,28 @@
        *  @since 2.4
        * 
        **/
  -    
  -    private void constructListenerBinding(IComponent component, String bindingName, ListenerBindingSpecification spec)
  -    {
  -        String location = Tapestry.getString("PageLoader.script-location", bindingName, component.getExtendedId());
  +
  +    private void constructListenerBinding(
  +        IComponent component,
  +        String bindingName,
  +        ListenerBindingSpecification spec)
  +    {
  +        String location =
  +            Tapestry.getString(
  +                "PageLoader.script-location",
  +                bindingName,
  +                component.getExtendedId());
   
           String language = spec.getLanguage();
  -        
  +
           // If not provided in the page or component specification, then
           // search for a default (factory default is "jython").
  -        
  +
           if (Tapestry.isNull(language))
  -            language = _engine.getPropertySource().getPropertyValue("net.sf.tapestry.default-script-language");
  -            
  +            language =
  +                _engine.getPropertySource().getPropertyValue(
  +                    "net.sf.tapestry.default-script-language");
  +
           IBinding binding = new ListenerBinding(component, language, location, spec.getScript());
   
           component.setBinding(bindingName, binding);
  @@ -454,13 +488,19 @@
   
                   _componentResolver.resolve(namespace, type);
   
  -                ComponentSpecification componentSpecification = _componentResolver.getSpecification();
  +                ComponentSpecification componentSpecification =
  +                    _componentResolver.getSpecification();
                   INamespace componentNamespace = _componentResolver.getNamespace();
   
                   // Instantiate the contained component.
   
                   IComponent component =
  -                    instantiateComponent(page, container, id, componentSpecification, componentNamespace);
  +                    instantiateComponent(
  +                        page,
  +                        container,
  +                        id,
  +                        componentSpecification,
  +                        componentNamespace);
   
                   // Add it, by name, to the container.
   
  @@ -473,7 +513,12 @@
                   // Now construct the component recusively; it gets its chance
                   // to create its subcomponents and set their bindings.
   
  -                constructComponent(cycle, page, component, componentSpecification, componentNamespace);
  +                constructComponent(
  +                    cycle,
  +                    page,
  +                    component,
  +                    componentSpecification,
  +                    componentNamespace);
               }
   
               addAssets(container, containerSpec);
  @@ -485,6 +530,11 @@
               // later.
   
               container.finishLoad(cycle, this, containerSpec);
  +
  +            // Finally, we create an initializer for each
  +            // specified property.
  +
  +            createPropertyInitializers(page, container, containerSpec);
           }
           catch (RuntimeException ex)
           {
  @@ -524,7 +574,8 @@
           INamespace componentNamespace = _componentResolver.getNamespace();
           ComponentSpecification spec = _componentResolver.getSpecification();
   
  -        IComponent result = instantiateComponent(page, container, componentId, spec, componentNamespace);
  +        IComponent result =
  +            instantiateComponent(page, container, componentId, spec, componentNamespace);
   
           container.addComponent(result);
   
  @@ -556,40 +607,34 @@
           String className = spec.getComponentClassName();
   
           if (Tapestry.isNull(className))
  -        {
  -            result = new BaseComponent();
  -        }
  -        else
  -        {
  +            className = BaseComponent.class.getName();
   
  -            Class componentClass = _resolver.findClass(className);
  +        Class componentClass = _enhancer.getEnhancedClass(spec, className);
   
  -            try
  -            {
  -                result = (IComponent) componentClass.newInstance();
  -
  -            }
  -            catch (ClassCastException ex)
  -            {
  -                throw new PageLoaderException(
  -                    Tapestry.getString("PageLoader.class-not-component", className),
  -                    container,
  -                    ex);
  -            }
  -            catch (Exception ex)
  -            {
  -                throw new PageLoaderException(
  -                    Tapestry.getString("PageLoader.unable-to-instantiate", className),
  -                    container,
  -                    ex);
  -            }
  -
  -            if (result instanceof IPage)
  -                throw new PageLoaderException(
  -                    Tapestry.getString("PageLoader.page-not-allowed", result.getExtendedId()),
  -                    result);
  +        try
  +        {
  +            result = (IComponent) componentClass.newInstance();
   
           }
  +        catch (ClassCastException ex)
  +        {
  +            throw new PageLoaderException(
  +                Tapestry.getString("PageLoader.class-not-component", className),
  +                container,
  +                ex);
  +        }
  +        catch (Exception ex)
  +        {
  +            throw new PageLoaderException(
  +                Tapestry.getString("PageLoader.unable-to-instantiate", className),
  +                container,
  +                ex);
  +        }
  +
  +        if (result instanceof IPage)
  +            throw new PageLoaderException(
  +                Tapestry.getString("PageLoader.page-not-allowed", result.getExtendedId()),
  +                result);
   
           result.setNamespace(namespace);
           result.setSpecification(spec);
  @@ -627,18 +672,22 @@
           if (Tapestry.isNull(className))
           {
               if (LOG.isDebugEnabled())
  -                LOG.debug("Page " + namespace.constructQualifiedName(name) + " does not specify a component class.");
  +                LOG.debug(
  +                    "Page "
  +                        + namespace.constructQualifiedName(name)
  +                        + " does not specify a component class.");
   
  -            className = _engine.getPropertySource().getPropertyValue("net.sf.tapestry.default-page-class");
  +            className =
  +                _engine.getPropertySource().getPropertyValue("net.sf.tapestry.default-page-class");
   
               if (className == null)
                   className = BasePage.class.getName();
   
               if (LOG.isDebugEnabled())
  -                LOG.debug("Instantiating as class " + className);
  +                LOG.debug("Defaulting to class " + className);
           }
   
  -        Class pageClass = _resolver.findClass(className);
  +        Class pageClass = _enhancer.getEnhancedClass(spec, className);
   
           try
           {
  @@ -648,15 +697,22 @@
               result.setSpecification(spec);
               result.setName(name);
               result.setPageName(pageName);
  +            result.setPage(result);
               result.setLocale(_locale);
           }
           catch (ClassCastException ex)
           {
  -            throw new PageLoaderException(Tapestry.getString("PageLoader.class-not-page", className), name, ex);
  +            throw new PageLoaderException(
  +                Tapestry.getString("PageLoader.class-not-page", className),
  +                name,
  +                ex);
           }
           catch (Exception ex)
           {
  -            throw new PageLoaderException(Tapestry.getString("PageLoader.unable-to-instantiate", className), name, ex);
  +            throw new PageLoaderException(
  +                Tapestry.getString("PageLoader.unable-to-instantiate", className),
  +                name,
  +                ex);
           }
   
           return result;
  @@ -679,7 +735,11 @@
        *
        **/
   
  -    public IPage loadPage(String name, INamespace namespace, IRequestCycle cycle, ComponentSpecification specification)
  +    public IPage loadPage(
  +        String name,
  +        INamespace namespace,
  +        IRequestCycle cycle,
  +        ComponentSpecification specification)
           throws PageLoaderException
       {
           IPage page = null;
  @@ -712,7 +772,14 @@
           }
   
           if (LOG.isInfoEnabled())
  -            LOG.info("Loaded page " + page + " with " + _count + " components (maximum depth " + _maxDepth + ")");
  +            LOG.info(
  +                "Loaded page "
  +                    + page
  +                    + " with "
  +                    + _count
  +                    + " components (maximum depth "
  +                    + _maxDepth
  +                    + ")");
   
           return page;
       }
  @@ -750,6 +817,57 @@
   
               component.addAsset(name, asset);
           }
  +    }
  +
  +    /**
  +     *  Invoked from 
  +     *  {@link #constructComponent(IRequestCycle, IPage, IComponent, ComponentSpecification, INamespace)}
  +     *  after {@link IComponent#finishLoad(IRequestCycle, IPageLoader, ComponentSpecification)}
  +     *  is invoked.  This iterates over any
  +     *  {@link net.sf.tapestry.spec.PropertySpecification}s for the component,
  +     *  create an initializer for each.
  +     * 
  +     **/
  +
  +    private void createPropertyInitializers(
  +        IPage page,
  +        IComponent component,
  +        ComponentSpecification spec)
  +    {
  +        List names = spec.getPropertySpecificationNames();
  +        int count = names.size();
  +
  +        for (int i = 0; i < count; i++)
  +        {
  +            String name = (String) names.get(i);
  +            PropertySpecification ps = spec.getPropertySpecification(name);
  +
  +            String expression = ps.getInitialValue();
  +            Object initialValue = null;
  +
  +            // If no initial value expression is provided, then read the current
  +            // property of the expression.  This may be null, or may be
  +            // a value set in finishLoad() (via an abstract accessor).
  +
  +            if (Tapestry.isNull(expression))
  +            {
  +                initialValue = OgnlUtils.get(name, _resolver, component);
  +            }
  +            else
  +            {
  +                // Evaluate the expression and update the property.
  +
  +                initialValue = OgnlUtils.get(expression, _resolver, component);
  +
  +                OgnlUtils.set(name, _resolver, component, initialValue);
  +            }
  +
  +            PageDetachListener initializer =
  +                new PropertyInitializer(_resolver, component, name, initialValue);
  +
  +            page.addPageDetachListener(initializer);
  +        }
  +
       }
   
       /**
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/pageload/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/pageload/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:50:08 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:31 -0000	1.4
  @@ -9,7 +9,7 @@
   <p>Classes used when loading pages (and thier heirarchies of components) from thier
   specifications, as well as organizaing thier templates.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/pageload/PropertyInitializer.java
  
  Index: PropertyInitializer.java
  ===================================================================
  package net.sf.tapestry.pageload;
  
  import net.sf.tapestry.IComponent;
  import net.sf.tapestry.IResourceResolver;
  import net.sf.tapestry.event.PageDetachListener;
  import net.sf.tapestry.event.PageEvent;
  import net.sf.tapestry.util.prop.OgnlUtils;
  
  /**
   *  Given a component, a property and a value, this object will
   *  reset the property to the value whenever the page
   *  (containing the component) is detached.  This is related
   *  to support for {@link net.sf.tapestry.spec.PropertySpecification}s.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: PropertyInitializer.java,v 1.1 2003/01/24 00:49:31 hlship Exp $
   *  @since 2.4
   **/
  
  public class PropertyInitializer implements PageDetachListener
  {
      private IResourceResolver _resolver;
      private IComponent _component;
      private String _propertyName;
      private Object _value;
  
      public PropertyInitializer(
          IResourceResolver resolver,
          IComponent component,
          String propertyName,
          Object value)
      {
          _resolver = resolver;
          _component = component;
          _propertyName = propertyName;
          _value = value;
      }
  
      public void pageDetached(PageEvent event)
      {
          OgnlUtils.set(_propertyName, _resolver, _component, _value);
      }
  
  }
  
  
  
  1.27      +3 -2      jakarta-tapestry/examples/Tutorial/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Tutorial/build.xml,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- build.xml	17 Jan 2003 17:45:30 -0000	1.26
  +++ build.xml	24 Jan 2003 00:49:31 -0000	1.27
  @@ -18,7 +18,8 @@
       <pathelement location="${lib.ext.dir}/${jfreechart.jar}"/>
       <pathelement location="${lib.ext.dir}/${jakarta-oro.jar}"/>
       <pathelement location="${lib.ext.dir}/${ognl.jar}"/>
  -    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>
  +    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>
       <pathelement location="${framework.jar}"/>
       <pathelement location="${contrib.jar}"/>   
     </path>
  
  
  
  1.7       +4 -3      jakarta-tapestry/framework/src/net/sf/tapestry/link/ExternalLink.java
  
  Index: ExternalLink.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/link/ExternalLink.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ExternalLink.java	13 Jan 2003 03:33:07 -0000	1.6
  +++ ExternalLink.java	24 Jan 2003 00:49:32 -0000	1.7
  @@ -56,6 +56,7 @@
   
   import net.sf.tapestry.IEngineService;
   import net.sf.tapestry.IRequestCycle;
  +import net.sf.tapestry.Tapestry;
   
   /**
    *  A component for creating a link to {@link IExternalPage} using the 
  @@ -78,13 +79,13 @@
       private String _targetPage;
   
       /**
  -     *  Returns {@link IEngineService#EXTERNAL_SERVICE}.
  +     *  Returns {@link Tapestry#EXTERNAL_SERVICE}.
        *
        **/
   
       protected String getServiceName()
       {
  -        return IEngineService.EXTERNAL_SERVICE;
  +        return Tapestry.EXTERNAL_SERVICE;
       }
   
       protected Object[] getServiceParameters(IRequestCycle cycle)
  
  
  
  1.7       +4 -3      jakarta-tapestry/framework/src/net/sf/tapestry/link/PageLink.java
  
  Index: PageLink.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/link/PageLink.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- PageLink.java	13 Jan 2003 03:33:07 -0000	1.6
  +++ PageLink.java	24 Jan 2003 00:49:32 -0000	1.7
  @@ -58,6 +58,7 @@
   import net.sf.tapestry.INamespace;
   import net.sf.tapestry.IRequestCycle;
   import net.sf.tapestry.RequestCycleException;
  +import net.sf.tapestry.Tapestry;
   
   /**
    *  A component for creating a navigation link to another page, 
  @@ -79,13 +80,13 @@
       private INamespace _targetNamespace;
   
       /**
  -     *  Returns {@link IEngineService#PAGE_SERVICE}.
  +     *  Returns {@link Tapestry#PAGE_SERVICE}.
        *
        **/
   
       protected String getServiceName()
       {
  -        return IEngineService.PAGE_SERVICE;
  +        return Tapestry.PAGE_SERVICE;
       }
   
       /**
  
  
  
  1.8       +6 -5      jakarta-tapestry/framework/src/net/sf/tapestry/link/DirectLink.java
  
  Index: DirectLink.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/link/DirectLink.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- DirectLink.java	13 Jan 2003 03:33:07 -0000	1.7
  +++ DirectLink.java	24 Jan 2003 00:49:32 -0000	1.8
  @@ -60,10 +60,10 @@
   import net.sf.tapestry.IActionListener;
   import net.sf.tapestry.IBinding;
   import net.sf.tapestry.IDirect;
  -import net.sf.tapestry.IEngineService;
   import net.sf.tapestry.IRequestCycle;
   import net.sf.tapestry.RequestCycleException;
   import net.sf.tapestry.RequiredParameterException;
  +import net.sf.tapestry.Tapestry;
   
   /**
    *  A component for creating a link using the direct service; used for actions that
  @@ -108,13 +108,13 @@
       }
   
       /**
  -     *  Returns {@link IEngineService#DIRECT_SERVICE}.
  +     *  Returns {@link net.sf.tapestry.Tapestry#DIRECT_SERVICE}.
        *
        **/
   
       protected String getServiceName()
       {
  -        return IEngineService.DIRECT_SERVICE;
  +        return Tapestry.DIRECT_SERVICE;
       }
   
       protected Object[] getServiceParameters(IRequestCycle cycle)
  @@ -198,7 +198,8 @@
   
           try
           {
  -            result = (IActionListener) _listenerBinding.getObject("listener", IActionListener.class);
  +            result =
  +                (IActionListener) _listenerBinding.getObject("listener", IActionListener.class);
   
           }
           catch (BindingException ex)
  
  
  
  1.5       +8 -9      jakarta-tapestry/framework/src/net/sf/tapestry/link/ActionLink.java
  
  Index: ActionLink.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/link/ActionLink.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ActionLink.java	13 Jan 2003 03:33:07 -0000	1.4
  +++ ActionLink.java	24 Jan 2003 00:49:32 -0000	1.5
  @@ -57,10 +57,10 @@
   import net.sf.tapestry.IAction;
   import net.sf.tapestry.IActionListener;
   import net.sf.tapestry.IBinding;
  -import net.sf.tapestry.IEngineService;
   import net.sf.tapestry.IRequestCycle;
   import net.sf.tapestry.RenderRewoundException;
   import net.sf.tapestry.RequestCycleException;
  +import net.sf.tapestry.Tapestry;
   
   /**
    *  A component for creating a link that is handled using the action service.
  @@ -94,24 +94,24 @@
       {
           if (_statefulBinding == null)
               return true;
  -            
  -         return _statefulBinding.getBoolean();
  +
  +        return _statefulBinding.getBoolean();
       }
   
       /**
  -     *  Returns {@link IEngineService#ACTION_SERVICE}.
  +     *  Returns {@link Tapestry#ACTION_SERVICE}.
        * 
        **/
   
       protected String getServiceName()
       {
  -        return IEngineService.ACTION_SERVICE;
  +        return Tapestry.ACTION_SERVICE;
       }
   
       protected Object[] getServiceParameters(IRequestCycle cycle) throws RequestCycleException
       {
           String actionId;
  - 
  +
           actionId = cycle.getNextActionId();
   
           if (cycle.isRewound(this))
  @@ -123,7 +123,7 @@
   
           return new Object[] { actionId };
       }
  -    
  +
       public IBinding getStatefulBinding()
       {
           return _statefulBinding;
  @@ -133,7 +133,6 @@
       {
           _statefulBinding = statefulBinding;
       }
  -
   
       public IActionListener getListener()
       {
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/link/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/link/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 May 2002 21:37:14 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:32 -0000	1.5
  @@ -20,7 +20,7 @@
   to include DHTML and JavaScript that preloads the images and changes the displayed image as the
   mouse enters and exits the "hot" area defined by the link.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.4       +4 -2      jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestExternal.xml
  
  Index: TestExternal.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestExternal.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestExternal.xml	17 Jan 2003 17:41:28 -0000	1.3
  +++ TestExternal.xml	24 Jan 2003 00:49:32 -0000	1.4
  @@ -58,7 +58,9 @@
   	
   	</assert-output-matches>
   	
  -	<assert name="HttpSession created" expression="request.session != null"/>
  +	<assert name="HttpSession created">
  +	request.session != null
  +	</assert>
   	
     </request>
     	
  
  
  
  1.3       +15 -13    jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestPersistentProperties.xml
  
  Index: TestPersistentProperties.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestPersistentProperties.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestPersistentProperties.xml	17 Jan 2003 17:41:28 -0000	1.2
  +++ TestPersistentProperties.xml	24 Jan 2003 00:49:32 -0000	1.3
  @@ -56,9 +56,10 @@
   Active page names: [Home] 		
   		</assert-output>
   								
  -		<assert name="Session Attribute"
  -			expression='request.session.getAttribute("app/Home/message").equals("Changed")'
  -			/>				
  +		<assert name="Session Attribute">
  +	    request.session.getAttribute("app/Home/message").equals("Changed")
  +		</assert>
  +					
   	</request>
   	
   	<!-- Return to the page, check for the change.  -->
  @@ -149,9 +150,9 @@
   Active page names: [Home, Two] 		
   		</assert-output>				
   		
  -		<assert name="Session Attribute"
  -			expression='request.session.getAttribute("app/Two/$Nested/message").equals("Changed")'
  -			/>				
  +		<assert name="Session Attribute">
  +		request.session.getAttribute("app/Two/$Nested/message").equals("Changed")
  +		</assert>		
   					
   	</request>
   	
  @@ -238,9 +239,9 @@
   EJB is FakeEJBObject[997]
   		</assert-output>			
   				
  -		<assert 
  -			name="Stored Value"
  -			expression='request.session.getAttribute("app/Three/ejb").getClass().getName().equals("net.sf.tapestry.record.EJBWrapper")'/>
  +		<assert name="Stored Value">
  +		request.session.getAttribute("app/Three/ejb").getClass().getName().equals("net.sf.tapestry.record.EJBWrapper")
  +		</assert>
   		
   	</request>
   	
  @@ -287,9 +288,10 @@
   EJB is FakeEJBObject[997]
   		</assert-output>		
   		
  -		<assert 
  -			name="Attribute missing."
  -			expression='request.session.getAttribute("app/Three/ejb") == null'/>
  +		<assert name="Attribute missing">
  +		request.session.getAttribute("app/Three/ejb") == null
  +		</assert>
  +		
   	</request>
   			
   	<!-- Check that the value is now gone. -->
  
  
  
  1.4       +4 -2      jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestSimple.xml
  
  Index: TestSimple.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestSimple.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TestSimple.xml	17 Jan 2003 17:41:28 -0000	1.3
  +++ TestSimple.xml	24 Jan 2003 00:49:32 -0000	1.4
  @@ -49,7 +49,9 @@
   ]]>
     	 </assert-output>
     
  -  	  <assert name="Session not created" expression="request.session == null"/>
  +  	  <assert name="Session not created">
  +  	  request.session == null
  +  	  </assert>
     	  
     	</request>
     	
  
  
  
  1.7       +4 -2      jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestLibrary.xml
  
  Index: TestLibrary.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestLibrary.xml,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- TestLibrary.xml	17 Jan 2003 17:41:28 -0000	1.6
  +++ TestLibrary.xml	24 Jan 2003 00:49:32 -0000	1.7
  @@ -95,7 +95,9 @@
   ]]>
     	  </assert-output>	
   	
  -	<assert name="HttpSession created" expression="request.session != null"/>
  +	<assert name="HttpSession created">
  +	request.session != null
  +	</assert>
   	
     </request>
     
  
  
  
  1.14      +11 -1     jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/MockTestCase.java
  
  Index: MockTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/MockTestCase.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- MockTestCase.java	22 Jan 2003 16:51:17 -0000	1.13
  +++ MockTestCase.java	24 Jan 2003 00:49:32 -0000	1.14
  @@ -94,6 +94,16 @@
       // implicitly define tests based on the found XML files?  Possibly
       // in a static suite() method.
   
  +	/**
  +	 *  Tests related to specified properties.
  +	 * 
  +	 **/
  +	
  +	public void testPropertySpecification()
  +	throws Exception
  +	{
  +		attempt("TestPropertySpecification.xml");
  +	}
   
   	/**
   	 *  Tests ability to override default template extension.
  
  
  
  1.13      +2 -2      jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/MockTester.java
  
  Index: MockTester.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/MockTester.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- MockTester.java	22 Jan 2003 16:51:17 -0000	1.12
  +++ MockTester.java	24 Jan 2003 00:49:32 -0000	1.13
  @@ -425,7 +425,7 @@
               Element a = (Element) l.get(i);
   
               String name = a.getAttributeValue("name");
  -            String expression = a.getAttributeValue("expression");
  +            String expression = a.getTextTrim();
   
               checkExpression(name, expression);
           }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/TestPropertySpecification.xml
  
  Index: TestPropertySpecification.xml
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  
  <!-- $Id: TestPropertySpecification.xml,v 1.1 2003/01/24 00:49:32 hlship Exp $ -->
  
  <mock-test>
      <context name="c9" root="context9"/>
  
    	<servlet name="app" class="net.sf.tapestry.ApplicationServlet"/>
  
  	<request>
    	  	  	  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Home</title>
  ]]>
  		</assert-output>
    	  	  	
  		<assert-output name="Initial Value">
  Initial value: []
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [boy]
  		</assert-output>
  			
  		<assert-output-matches name="List Items" subgroup="1">
  <![CDATA[
  <li>(.*?)</li>
  ]]>
  			<match>Gromit</match>
  			<match>is</match>
  			<match>a</match>
  			<match>good</match>
  			<match>boy</match>
  		</assert-output-matches>
   
  		<assert-regexp name="Page Class">
  <![CDATA[
  Page class: \[net\.sf\.tapestry\.html\.BasePage\$(.*?)\]
  ]]>	
  		</assert-regexp>
   
   
  	</request>
  	
  
  	<request>
    	  	  	  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Home</title>
  ]]>
  		</assert-output>
    	  	  	
  		<assert-output name="Initial Value">
  Initial value: []
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [boy]
  		</assert-output>
  			
  		<assert-output-matches name="List Items" subgroup="1">
  <![CDATA[
  <li>(.*?)</li>
  ]]>
  			<match>Gromit</match>
  			<match>is</match>
  			<match>a</match>
  			<match>good</match>
  			<match>boy</match>
  		</assert-output-matches>
  	</request>
  	
  	<request> 
  		<parameter name="service" value="page"/>
  		<parameter name="context" value="Two"/>	  	  	  	  	 	
   	  	  	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Two</title>
  ]]>
  		</assert-output>
  		 	  	  	
  		<assert-output name="Initial Value">
  Initial value: [15]
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [8]
  		</assert-output>
  
  		<assert-output-matches name="List Items" subgroup="1">
  <![CDATA[
  <li>(.*?)</li>
  ]]>
  			<match>2</match>
  			<match>4</match>
  			<match>6</match>
  			<match>8</match>
  		</assert-output-matches>			
  	</request>	
  	
  	<request> 
  		<parameter name="service" value="page"/>
  		<parameter name="context" value="Two"/>	  	  	  	  	 	
   	  	  	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Two</title>
  ]]>
  		</assert-output>
  		 	  	  	
  		<assert-output name="Initial Value">
  Initial value: [15]
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [8]
  		</assert-output>
  			
  	</request>	
  	
  	<request>
    	  	<parameter name="service" value="page"/>
    	  	<parameter name="context" value="Three"/>
    	  		  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Three</title>
  ]]>
  		</assert-output>
    	  	  	
  		<assert-output name="Initial Value">
  Initial value: [Tapestry]
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [Taxi]
  		</assert-output>
  			
  		<assert-output-matches name="List Items" subgroup="1">
  <![CDATA[
  <li>(.*?)</li>
  ]]>
  			<match>Crazy</match>
  			<match>Taxi</match>
  		</assert-output-matches>
   
  		<assert-regexp name="Page Class">
  <![CDATA[
  Page class: \[net\.sf\.tapestry\.junit\.mock\.c9\.Three\$(.*?)\]
  ]]>	
  		</assert-regexp>
   
   
  	</request>	
  	
  	<request>
    	  	<parameter name="service" value="page"/>
    	  	<parameter name="context" value="Three"/>
    	  		  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Three</title>
  ]]>
  		</assert-output>
    	  	  	
  		<assert-output name="Initial Value">
  Initial value: [Tapestry]
  		</assert-output>
  	
  		<assert-output name="Final Value">
  Final value: [Taxi]
  		</assert-output>
  	</request>
  		
  	<!-- Page Four includes an non-abstract accessor for the property, so it will
  	     cause an exception. -->
  	     		
  	<request>
    	  	<parameter name="service" value="page"/>
    	  	<parameter name="context" value="Four"/>
    	  		  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Exception</title>
  ]]>			
  		</assert-output>
  		
  		<assert-output name="Exception Message">
  Unable to enhance class net.sf.tapestry.junit.mock.c9.Four because it implements a non-abstract read method for property 'word'.
  		</assert-output>		
  		
  	</request>		
  	
  	<request>
    	  	<parameter name="service" value="page"/>
    	  	<parameter name="context" value="Five"/>
    	  		  	  	 	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Exception</title>
  ]]>			
  		</assert-output>
  		
  		<assert-output name="Exception Message">
  Unable to enhance class net.sf.tapestry.junit.mock.c9.Five because it implements a non-abstract write method for property 'word'.
  		</assert-output>		
  		
  	</request>		
  	
  	<!-- This test is about making sure the property type in the specification matches
  		 the actual property type (if the class declares abstract accessor methods). -->
  		 
  	<request> 
  		<parameter name="service" value="page"/>
  		<parameter name="context" value="Six"/>	  	  	  	  	 	
   	  	  	
  		<assert-output name="Page Title">
  <![CDATA[		
  <title>Exception</title>
  ]]>
  		</assert-output>
  		
  		<assert-output name="Exception Message">
  Unable to enhance class net.sf.tapestry.junit.mock.c9.Six because it contains property 'value' of type int, not the expected type long.
  		</assert-output>		
  
  	</request>			
  	
  	<request>
  		<parameter name="service" value="page"/>
  		<parameter name="context" value="Seven"/>
  		
  		<assert-output name="Page Title">
  <![CDATA[
  <title>Seven</title>
  ]]>
  		</assert-output>
  		
  		<assert-output-matches name="Values" subgroup="1">
  <![CDATA[
  value: \[(.*?)\]
  ]]>
  			<match>true</match>
  			<match>65</match>
  			<match>Z</match>
  			<match>97</match>
  			<match>100</match>
  			<match>32000000</match>
  			<match>-22.7</match>
  			<match>3.2</match>
  			<match>Magic</match>
  		</assert-output-matches>		
  		
  		<assert-output name="Link">
  <![CDATA[
  /c9/app?service=direct&amp;context=0/Seven/$DirectLink		
  ]]>
  		</assert-output>
  	</request>	
  	
  	<!-- Trigger the link and check for the changes in the page, and in persistent storage. -->
  	
  	<request>
  		<parameter name="service" value="direct"/>
  		<parameter name="context" value="0/Seven/$DirectLink"/>
  		
  		
  		<assert-output name="Page Title">
  <![CDATA[
  <title>Seven</title>
  ]]>
  		</assert-output>
  		
  		<assert-output-matches name="Values" subgroup="1">
  <![CDATA[
  value: \[(.*?)\]
  ]]>
  			<match>false</match>
  			<match>81</match>
  			<match>f</match>
  			<match>21</match>
  			<match>3097</match>
  			<match>132000001</match>
  			<match>-202.2</match>
  			<match>9.87</match>
  			<match>Marker</match>
  		</assert-output-matches>		
  		
  		<assert-output name="Link">
  <![CDATA[
  /c9/app?service=direct&amp;context=1/Seven/$DirectLink		
  ]]>
  		</assert-output>	
  		
  		<assert name="Persistent booleanValue">
  		request.session.getAttribute("app/Seven/booleanValue") == false
  		</assert>
  		
  		<assert name="Persistent byteValue">
  		request.session.getAttribute("app/Seven/byteValue") == 81
  		</assert>
  		
  		<assert name="Persistent charValue">
  		request.session.getAttribute("app/Seven/charValue") == 'f'
  		</assert>
  		
  		<assert name="Persistent shortValue">
  		request.session.getAttribute("app/Seven/shortValue") == 21
  		</assert>
  		
  		<assert name="Persistent intValue">
  		request.session.getAttribute("app/Seven/intValue") == 3097
  		</assert>
  		
  		<assert name="Persistent longValue">
  		request.session.getAttribute("app/Seven/longValue") == 132000001
  		</assert>
  		
  		<assert name="Persistent floatValue">
  		request.session.getAttribute("app/Seven/floatValue") == -202.2f
  		</assert>
  		
  		<assert name="Persistent doubleValue">
  		request.session.getAttribute("app/Seven/doubleValue") == 9.87
  		</assert>
  		
  		<assert name="Persistent stringValue">
  		request.session.getAttribute("app/Seven/stringValue") == "Marker"
  		</assert>
  		 	
  	</request>
  		
   </mock-test>
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/binding/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/binding/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	5 May 2002 21:04:02 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:32 -0000	1.2
  @@ -8,7 +8,7 @@
   
   <p>Implementations of {@link net.sf.tapestry.IBinding}.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/param/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/param/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	8 May 2002 21:21:52 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:32 -0000	1.2
  @@ -9,7 +9,7 @@
   Code to assist {@link net.sf.tapestry.IComponent} in setting JavaBeans properties 
   from bound parameters.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.22      +1 -0      jakarta-tapestry/.classpath
  
  Index: .classpath
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/.classpath,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- .classpath	17 Jan 2003 17:39:08 -0000	1.21
  +++ .classpath	24 Jan 2003 00:49:32 -0000	1.22
  @@ -27,5 +27,6 @@
       <classpathentry kind="lib" path="lib/ext/commons-lang-1.0.jar"/>
       <classpathentry kind="lib" path="lib/ext/ognl-2.3.0-opt.jar"/>
       <classpathentry kind="lib" path="lib/ext/bsf-2.3.0.jar"/>
  +    <classpathentry kind="lib" path="lib/ext/bcel-5.0.jar"/>
       <classpathentry kind="output" path="bin"/>
   </classpath>
  
  
  
  1.80      +20 -1     jakarta-tapestry/Readme.html
  
  Index: Readme.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/Readme.html,v
  retrieving revision 1.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- Readme.html	20 Jan 2003 20:34:39 -0000	1.79
  +++ Readme.html	24 Jan 2003 00:49:32 -0000	1.80
  @@ -188,6 +188,25 @@
   					<th><font color="white">Description</font>
   					</th>
   				</tr>
  +				
  +			
  +				<tr valign="top">
  +					<td>bcel-5.0.jar
  +					</td>
  +					<td>5.0
  +					</td>
  +					<td>Apache Software License
  +						<td>
  +						<a href="http://jakarta.apache.org/bcel">Byte Code Engineering Library</a>
  +						
  +							</td>
  +				</tr>
  +				
  +						
  +	<tr bgcolor="black">
  +					<td colspan="5" height="1"><IMG src="web/images/spacer.gif"></td>
  +				</tr>
  +												
   				<tr valign="top">
   					<td>bsf-2.0.3.jar
   					</td>
  
  
  
  1.64      +7 -2      jakarta-tapestry/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/build.xml,v
  retrieving revision 1.63
  retrieving revision 1.64
  diff -u -r1.63 -r1.64
  --- build.xml	20 Jan 2003 21:18:04 -0000	1.63
  +++ build.xml	24 Jan 2003 00:49:32 -0000	1.64
  @@ -31,6 +31,7 @@
   	<pathelement location="${lib.ext.dir}/${jakarta-oro.jar}"/>
   	<pathelement location="${lib.ext.dir}/${ognl.jar}"/>
       <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>
   	<pathelement location="config"/>
   </path>
   
  @@ -439,6 +440,7 @@
   			<exclude name="${commons-lang.jar}"/>
   			<exclude name="${commons-logging.jar}"/>
   			<exclude name="${bsf.jar}"/>
  +			<exclude name="${bcel.jar}"/>
   			
   			<!-- Match and include out-of-date versions -->
   			
  @@ -448,6 +450,7 @@
   			<include name="commons-logging*.jar"/>
   			<include name="commons-lang*.jar"/>
   			<include name="bsf*.jar"/>
  +			<include name="bcel*.jar"/>
   		</fileset>
   	</delete>
   		
  @@ -459,6 +462,7 @@
   			<include name="${commons-logging.jar}"/>
   			<include name="${commons-lang.jar}"/>
   			<include name="${bsf.jar}"/>
  +			<include name="${bcel.jar}"/>
   		</fileset>
   		<fileset dir="${jboss.server.default.dir}/lib">
   		
  @@ -607,7 +611,8 @@
         <include name="${jakarta-oro.jar}"/>
         <include name="${log4j.jar}"/>
         <include name="${ognl.jar}"/>
  -      <include name="${bsf.jar}"/>      
  +      <include name="${bsf.jar}"/> 
  +      <include name="${bcel.jar}"/>     
       </fileset>
     </copy>  
   </target>
  
  
  
  1.3       +9 -6      jakarta-tapestry/TODO.html
  
  Index: TODO.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/TODO.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TODO.html	17 Jan 2003 17:39:08 -0000	1.2
  +++ TODO.html	24 Jan 2003 00:49:33 -0000	1.3
  @@ -18,11 +18,7 @@
   <li>Deal with character sets and localization properly
     <LI>Handle change of locale correctly, by reloading new instance of page in 
     proper locale
  -  <LI>Declarative transient properties - define transient properties in spec, 
  -  Tapestry builds subclass with&nbsp;instance variables, accessors and 
  -  initialize() to handle
  -  <LI>Declarative persistant properties - as with transient, but properties are 
  -  made persistant
  +
     <LI>Improved User's Guide to replace existing Developer's 
     Guide
     <LI>Fill out the test suite and code coverage, reach 85% or better
  @@ -30,6 +26,13 @@
     <LI>Resolve GPL issues around McKoiDBMBean
     <LI><EM>More to come ...</EM></LI>      
   </ul>
  +
  +<h2>Completed items in 2.4</h1>
  +  <LI>Declarative transient properties - define transient properties in spec, 
  +  Tapestry builds subclass with&nbsp;instance variables, accessors and 
  +  initialize() <b>HLS</b>
  +  <LI>Declarative persistant properties - as with transient, but properties are 
  +  made persistant <b>HLS</b>
   
   </body>
   </html>
  
  
  
  1.24      +3 -2      jakarta-tapestry/examples/Vlib/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/build.xml,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- build.xml	17 Jan 2003 17:45:26 -0000	1.23
  +++ build.xml	24 Jan 2003 00:49:33 -0000	1.24
  @@ -15,7 +15,8 @@
       <pathelement location="${lib.ext.dir}/javax.xml.jaxp.jar"/>
       <pathelement location="${lib.ext.dir}/org.apache.crimson.jar"/>
       <pathelement location="${lib.ext.dir}/${ognl.jar}"/>
  -    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>    
  +    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>   
       <pathelement location="${framework.jar}"/>
       <pathelement location="${contrib.jar}"/>
       <pathelement location="${vlibbeans.jar}"/>
  
  
  
  1.21      +3 -2      jakarta-tapestry/junit/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/build.xml,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- build.xml	17 Jan 2003 17:41:31 -0000	1.20
  +++ build.xml	24 Jan 2003 00:49:33 -0000	1.21
  @@ -36,7 +36,8 @@
       <pathelement location="${lib.ext.dir}/junit.jar"/>
       <pathelement location="${lib.ext.dir}/${jakarta-oro.jar}"/> 
       <pathelement location="${lib.ext.dir}/${ognl.jar}"/>
  -    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>    
  +    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>  
       <pathelement location="${jython.dir}/jython.jar"/>
       <pathelement location="${local.lib.dir}/${jdom.jar}"/> 
     </path>
  
  
  
  1.9       +11 -6     jakarta-tapestry/framework/src/net/sf/tapestry/engine/ResetService.java
  
  Index: ResetService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/ResetService.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ResetService.java	17 Jan 2003 17:40:24 -0000	1.8
  +++ ResetService.java	24 Jan 2003 00:49:33 -0000	1.9
  @@ -88,26 +88,31 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (Tapestry.size(parameters) != 0)
  -            throw new IllegalArgumentException(Tapestry.getString("service-no-parameters", RESET_SERVICE));
  +            throw new IllegalArgumentException(
  +                Tapestry.getString("service-no-parameters", Tapestry.RESET_SERVICE));
   
           String[] context = new String[1];
           context[0] = component.getPage().getPageName();
   
  -        return assembleGesture(cycle, RESET_SERVICE, context, null, true);
  +        return assembleGesture(cycle, Tapestry.RESET_SERVICE, context, null, true);
       }
   
       public String getName()
       {
  -        return RESET_SERVICE;
  +        return Tapestry.RESET_SERVICE;
       }
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws RequestCycleException, ServletException, IOException
       {
           String[] context = getServiceContext(cycle.getRequestContext());
   
           if (Tapestry.size(context) != 1)
  -            throw new ApplicationRuntimeException(Tapestry.getString("service-single-parameter", RESET_SERVICE));
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString("service-single-parameter", Tapestry.RESET_SERVICE));
   
           String pageName = context[0];
   
  
  
  
  1.7       +9 -5      jakarta-tapestry/framework/src/net/sf/tapestry/engine/HomeService.java
  
  Index: HomeService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/HomeService.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- HomeService.java	13 Jan 2003 03:33:20 -0000	1.6
  +++ HomeService.java	24 Jan 2003 00:49:33 -0000	1.7
  @@ -87,12 +87,16 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (Tapestry.size(parameters) != 0)
  -            throw new IllegalArgumentException(Tapestry.getString("service-no-parameters", HOME_SERVICE));
  +            throw new IllegalArgumentException(
  +                Tapestry.getString("service-no-parameters", Tapestry.HOME_SERVICE));
   
  -        return assembleGesture(cycle, HOME_SERVICE, null, null, true);
  +        return assembleGesture(cycle, Tapestry.HOME_SERVICE, null, null, true);
       }
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws RequestCycleException, ServletException, IOException
       {
   
  @@ -111,7 +115,7 @@
   
       public String getName()
       {
  -        return HOME_SERVICE;
  +        return Tapestry.HOME_SERVICE;
       }
   
   }
  
  
  
  1.12      +10 -12    jakarta-tapestry/framework/src/net/sf/tapestry/engine/AbstractService.java
  
  Index: AbstractService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/AbstractService.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- AbstractService.java	13 Jan 2003 03:33:20 -0000	1.11
  +++ AbstractService.java	24 Jan 2003 00:49:33 -0000	1.12
  @@ -128,11 +128,11 @@
   
       protected String[] getServiceContext(RequestContext context)
       {
  -        String raw = context.getParameter(CONTEXT_QUERY_PARMETER_NAME);
  -        
  +        String raw = context.getParameter(Tapestry.CONTEXT_QUERY_PARMETER_NAME);
  +
           if (raw == null)
               return null;
  -            
  +
           return new StringSplitter('/').splitToArray(raw);
       }
   
  @@ -144,18 +144,16 @@
       protected Object[] getParameters(IRequestCycle cycle)
       {
           RequestContext context = cycle.getRequestContext();
  -        
  -        String[] squeezed = 
  -            context.getParameters(PARAMETERS_QUERY_PARAMETER_NAME);
  -            
  +
  +        String[] squeezed = context.getParameters(Tapestry.PARAMETERS_QUERY_PARAMETER_NAME);
  +
           if (Tapestry.size(squeezed) == 0)
               return squeezed;
  -            
  +
           try
           {
  -            DataSqueezer squeezer =
  -                cycle.getEngine().getDataSqueezer();
  -                
  +            DataSqueezer squeezer = cycle.getEngine().getDataSqueezer();
  +
               return squeezer.unsqueeze(squeezed);
           }
           catch (IOException ex)
  
  
  
  1.11      +11 -6     jakarta-tapestry/framework/src/net/sf/tapestry/engine/ActionService.java
  
  Index: ActionService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/ActionService.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ActionService.java	17 Jan 2003 17:40:24 -0000	1.10
  +++ ActionService.java	24 Jan 2003 00:49:33 -0000	1.11
  @@ -103,7 +103,8 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (parameters == null || parameters.length != 1)
  -            throw new IllegalArgumentException(Tapestry.getString("service-single-parameter", ACTION_SERVICE));
  +            throw new IllegalArgumentException(
  +                Tapestry.getString("service-single-parameter", Tapestry.ACTION_SERVICE));
   
           String stateful = cycle.getEngine().isStateful() ? STATEFUL_ON : STATEFUL_OFF;
           IPage componentPage = component.getPage();
  @@ -128,10 +129,13 @@
   
           serviceContext[i++] = component.getIdPath();
   
  -        return assembleGesture(cycle, ACTION_SERVICE, serviceContext, null, true);
  +        return assembleGesture(cycle, Tapestry.ACTION_SERVICE, serviceContext, null, true);
       }
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws RequestCycleException, ServletException, IOException
       {
           IAction action = null;
  @@ -144,7 +148,8 @@
               count = serviceContext.length;
   
           if (count != 4 && count != 5)
  -            throw new ApplicationRuntimeException(Tapestry.getString("ActionService.context-parameters"));
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString("ActionService.context-parameters"));
   
           boolean complex = count == 5;
   
  @@ -214,7 +219,7 @@
   
       public String getName()
       {
  -        return ACTION_SERVICE;
  +        return Tapestry.ACTION_SERVICE;
       }
   
   }
  
  
  
  1.41      +99 -21    jakarta-tapestry/framework/src/net/sf/tapestry/engine/AbstractEngine.java
  
  Index: AbstractEngine.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/AbstractEngine.java,v
  retrieving revision 1.40
  retrieving revision 1.41
  diff -u -r1.40 -r1.41
  --- AbstractEngine.java	20 Jan 2003 15:07:28 -0000	1.40
  +++ AbstractEngine.java	24 Jan 2003 00:49:33 -0000	1.41
  @@ -79,6 +79,7 @@
   
   import net.sf.tapestry.ApplicationRuntimeException;
   import net.sf.tapestry.ApplicationServlet;
  +import net.sf.tapestry.IComponentClassEnhancer;
   import net.sf.tapestry.IComponentStringsSource;
   import net.sf.tapestry.IEngine;
   import net.sf.tapestry.IEngineService;
  @@ -103,6 +104,7 @@
   import net.sf.tapestry.StaleLinkException;
   import net.sf.tapestry.StaleSessionException;
   import net.sf.tapestry.Tapestry;
  +import net.sf.tapestry.enhance.DefaultComponentClassEnhancer;
   import net.sf.tapestry.listener.ListenerMap;
   import net.sf.tapestry.pageload.PageSource;
   import net.sf.tapestry.spec.IApplicationSpecification;
  @@ -395,11 +397,19 @@
        *  in the servlet context.
        * 
        *  @since 2.3
  -     * 
  +     *
        **/
   
       protected static final String PROPERTY_SOURCE_NAME = "net.sf.tapestry.PropertySource";
   
  +    /**
  +     *  A shared instance of {@link IPropertySource}
  +     *  
  +     *  @since 2.4
  +     *  @see #createPropertySource(RequestContext)
  +     * 
  +     **/
  +
       private transient IPropertySource _propertySource;
   
       /**
  @@ -417,6 +427,7 @@
        *  A shared instance of {@link Pool}.
        * 
        *  @since 2.4
  +     *  @see #createPool(RequestContext)
        * 
        **/
   
  @@ -425,6 +436,26 @@
       protected static final String POOL_NAME = "net.sf.tapestry.Pool";
   
       /**
  +     *  Name of a shared instance of {@link net.sf.tapestry.IComponentClassEnhancer}
  +     *  stored in the {@link ServletContext}.
  +     * 
  +     *  @since 2.4
  +     * 
  +     **/
  +
  +    protected static final String ENHANCER_NAME = "net.sf.tapestry.ComponentClassEnhancer";
  +
  +    /**
  +     *  A shared instance of {@link net.sf.tapestry.IComponentClassEnhancer}.
  +     * 
  +     *  @since 2.4
  +     *  @see #createComponentClassEnhancer(RequestContext)
  +     * 
  +     **/
  +
  +    private transient IComponentClassEnhancer _enhancer;
  +
  +    /**
        *  Sets the Exception page's exception property, then renders the Exception page.
        *
        *  <p>If the render throws an exception, then copious output is sent to
  @@ -840,7 +871,7 @@
                   String serviceName = extractServiceName(context);
   
                   if (Tapestry.isNull(serviceName))
  -                    serviceName = IEngineService.HOME_SERVICE;
  +                    serviceName = Tapestry.HOME_SERVICE;
   
                   service = getService(serviceName);
   
  @@ -892,14 +923,21 @@
           }
           finally
           {
  -            cycle.cleanup();
  +            try
  +            {
  +                cycle.cleanup();
   
  -            // Closing the buffered output closes the underlying stream as well.
  +                // Closing the buffered output closes the underlying stream as well.
   
  -            if (output != null)
  -                output.forceFlush();
  +                if (output != null)
  +                    output.forceFlush();
   
  -            cleanupAfterRequest(cycle);
  +                cleanupAfterRequest(cycle);
  +            }
  +            catch (Exception ex)
  +            {
  +                reportException(Tapestry.getString("AbstractEngine.exception-during-cleanup"), ex);
  +            }
   
               if (_disableCaching)
               {
  @@ -909,7 +947,9 @@
                   }
                   catch (Exception ex)
                   {
  -                    LOG.warn("Exception thrown while clearing caches.", ex);
  +                    reportException(
  +                        Tapestry.getString("AbstractEngine.exception-during-cache-clear"),
  +                        ex);
                   }
               }
   
  @@ -1003,6 +1043,7 @@
           _templateSource.reset();
           _scriptSource.reset();
           _stringsSource.reset();
  +        _enhancer.reset();
       }
   
       /**
  @@ -1044,6 +1085,7 @@
        *
        *  <p>In addition, this method locates and/or creates the:
        *  <ul>
  +     *  <li>{@link IComponentClassEnhancer}
        *  <li>{@link Pool}
        *  <li>{@link ITemplateSource} 
        *  <li>{@link ISpecificationSource}
  @@ -1101,9 +1143,23 @@
   
           String servletName = context.getServlet().getServletName();
   
  +        if (_enhancer == null)
  +        {
  +            String name = ENHANCER_NAME + ":" + servletName;
  +
  +            _enhancer = (IComponentClassEnhancer) servletContext.getAttribute(name);
  +
  +            if (_enhancer == null)
  +            {
  +                _enhancer = createComponentClassEnhancer(context);
  +
  +                servletContext.setAttribute(name, _enhancer);
  +            }
  +        }
  +
           if (_pool == null)
           {
  -            String name = POOL_NAME + "." + servletName;
  +            String name = POOL_NAME + ":" + servletName;
   
               _pool = (Pool) servletContext.getAttribute(name);
   
  @@ -1117,7 +1173,7 @@
   
           if (_templateSource == null)
           {
  -            String name = TEMPLATE_SOURCE_NAME + "." + servletName;
  +            String name = TEMPLATE_SOURCE_NAME + ":" + servletName;
   
               _templateSource = (ITemplateSource) servletContext.getAttribute(name);
   
  @@ -1131,7 +1187,7 @@
   
           if (_specificationSource == null)
           {
  -            String name = SPECIFICATION_SOURCE_NAME + "." + servletName;
  +            String name = SPECIFICATION_SOURCE_NAME + ":" + servletName;
   
               _specificationSource = (ISpecificationSource) servletContext.getAttribute(name);
   
  @@ -1145,7 +1201,7 @@
   
           if (_pageSource == null)
           {
  -            String name = PAGE_SOURCE_NAME + "." + servletName;
  +            String name = PAGE_SOURCE_NAME + ":" + servletName;
   
               _pageSource = (IPageSource) servletContext.getAttribute(name);
   
  @@ -1159,7 +1215,7 @@
   
           if (_scriptSource == null)
           {
  -            String name = SCRIPT_SOURCE_NAME + "." + servletName;
  +            String name = SCRIPT_SOURCE_NAME + ":" + servletName;
   
               _scriptSource = (IScriptSource) servletContext.getAttribute(name);
   
  @@ -1173,7 +1229,7 @@
   
           if (_serviceMap == null)
           {
  -            String name = SERVICE_MAP_NAME + "." + servletName;
  +            String name = SERVICE_MAP_NAME + ":" + servletName;
   
               _serviceMap = (Map) servletContext.getAttribute(name);
   
  @@ -1187,7 +1243,7 @@
   
           if (_stringsSource == null)
           {
  -            String name = STRINGS_SOURCE_NAME + "." + servletName;
  +            String name = STRINGS_SOURCE_NAME + ":" + servletName;
   
               _stringsSource = (IComponentStringsSource) servletContext.getAttribute(name);
   
  @@ -1201,7 +1257,7 @@
   
           if (_dataSqueezer == null)
           {
  -            String name = DATA_SQUEEZER_NAME + "." + servletName;
  +            String name = DATA_SQUEEZER_NAME + ":" + servletName;
   
               _dataSqueezer = (DataSqueezer) servletContext.getAttribute(name);
   
  @@ -1215,7 +1271,7 @@
   
           if (_propertySource == null)
           {
  -            String name = PROPERTY_SOURCE_NAME + "." + servletName;
  +            String name = PROPERTY_SOURCE_NAME + ":" + servletName;
   
               _propertySource = (IPropertySource) servletContext.getAttribute(name);
   
  @@ -1229,7 +1285,7 @@
   
           if (_global == null)
           {
  -            String name = GLOBAL_NAME + "." + servletName;
  +            String name = GLOBAL_NAME + ":" + servletName;
   
               _global = servletContext.getAttribute(name);
   
  @@ -1925,7 +1981,7 @@
        *  specific services with unusual URL encoding rules.
        * 
        *  <p>This implementation simply extracts the value for
  -     *  query parameter {@link IEngineService#SERVICE_QUERY_PARAMETER_NAME}.
  +     *  query parameter {@link Tapestry#SERVICE_QUERY_PARAMETER_NAME}.
        * 
        *  @since 2.2
        * 
  @@ -1933,7 +1989,7 @@
   
       protected String extractServiceName(RequestContext context)
       {
  -        return context.getParameter(IEngineService.SERVICE_QUERY_PARAMETER_NAME);
  +        return context.getParameter(Tapestry.SERVICE_QUERY_PARAMETER_NAME);
       }
   
       /** @since 2.2 **/
  @@ -2097,6 +2153,28 @@
       public Pool getPool()
       {
           return _pool;
  +    }
  +
  +    /**
  +     * 
  +     *  Invoked from {@link #setupForRequest(RequestContext)}.  Creates
  +     *  a new instance of {@link DefaultComponentClassEnhancer}.  Subclasses
  +     *  may override to return a different object.
  +     * 
  +     *  @since 2.4
  +     * 
  +     **/
  +
  +    protected IComponentClassEnhancer createComponentClassEnhancer(RequestContext context)
  +    {
  +        return new DefaultComponentClassEnhancer(_resolver);
  +    }
  +
  +    /** @since 2.4 **/
  +
  +    public IComponentClassEnhancer getComponentClassEnhancer()
  +    {
  +        return _enhancer;
       }
   
   }
  
  
  
  1.8       +9 -5      jakarta-tapestry/framework/src/net/sf/tapestry/engine/RestartService.java
  
  Index: RestartService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/RestartService.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- RestartService.java	13 Jan 2003 03:33:20 -0000	1.7
  +++ RestartService.java	24 Jan 2003 00:49:33 -0000	1.8
  @@ -83,12 +83,16 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (Tapestry.size(parameters) != 0)
  -            throw new IllegalArgumentException(Tapestry.getString("service-no-parameters", RESTART_SERVICE));
  +            throw new IllegalArgumentException(
  +                Tapestry.getString("service-no-parameters", Tapestry.RESTART_SERVICE));
   
  -        return assembleGesture(cycle, RESTART_SERVICE, null, null, true);
  +        return assembleGesture(cycle, Tapestry.RESTART_SERVICE, null, null, true);
       }
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws RequestCycleException, ServletException, IOException
       {
           engine.restart(cycle);
  @@ -98,7 +102,7 @@
   
       public String getName()
       {
  -        return RESTART_SERVICE;
  +        return Tapestry.RESTART_SERVICE;
       }
   
   }
  
  
  
  1.8       +5 -5      jakarta-tapestry/framework/src/net/sf/tapestry/engine/PageService.java
  
  Index: PageService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/PageService.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- PageService.java	17 Jan 2003 17:40:25 -0000	1.7
  +++ PageService.java	24 Jan 2003 00:49:33 -0000	1.8
  @@ -85,9 +85,9 @@
       {
           if (Tapestry.size(parameters) != 1)
               throw new IllegalArgumentException(
  -                Tapestry.getString("service-single-parameter", PAGE_SERVICE));
  +                Tapestry.getString("service-single-parameter", Tapestry.PAGE_SERVICE));
   
  -        return assembleGesture(cycle, PAGE_SERVICE, (String[]) parameters, null, true);
  +        return assembleGesture(cycle, Tapestry.PAGE_SERVICE, (String[]) parameters, null, true);
   
       }
   
  @@ -102,7 +102,7 @@
   
           if (Tapestry.size(serviceContext) != 1)
               throw new ApplicationRuntimeException(
  -                Tapestry.getString("service-single-parameter", PAGE_SERVICE));
  +                Tapestry.getString("service-single-parameter", Tapestry.PAGE_SERVICE));
   
           String pageName = serviceContext[0];
   
  @@ -130,7 +130,7 @@
   
       public String getName()
       {
  -        return PAGE_SERVICE;
  +        return Tapestry.PAGE_SERVICE;
       }
   
   }
  
  
  
  1.10      +3 -3      jakarta-tapestry/framework/src/net/sf/tapestry/engine/DirectService.java
  
  Index: DirectService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/DirectService.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- DirectService.java	17 Jan 2003 17:40:25 -0000	1.9
  +++ DirectService.java	24 Jan 2003 00:49:33 -0000	1.10
  @@ -131,7 +131,7 @@
           context[i++] = componentPage.getPageName();
           context[i++] = component.getIdPath();
   
  -        return assembleGesture(cycle, DIRECT_SERVICE, context, parameters, true);
  +        return assembleGesture(cycle, Tapestry.DIRECT_SERVICE, context, parameters, true);
       }
   
       public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  @@ -222,6 +222,6 @@
   
       public String getName()
       {
  -        return DIRECT_SERVICE;
  +        return Tapestry.DIRECT_SERVICE;
       }
   }
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/engine/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	5 May 2002 21:04:01 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:33 -0000	1.2
  @@ -13,7 +13,7 @@
   {@link net.sf.tapestry.engine.RequestCycle} 
   (which implements {@link net.sf.tapestry.IRequestCycle}).
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.10      +13 -9     jakarta-tapestry/framework/src/net/sf/tapestry/engine/ExternalService.java
  
  Index: ExternalService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/engine/ExternalService.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ExternalService.java	13 Jan 2003 03:33:20 -0000	1.9
  +++ ExternalService.java	24 Jan 2003 00:49:33 -0000	1.10
  @@ -148,18 +148,22 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (parameters == null || parameters.length == 0)
  -            throw new ApplicationRuntimeException(Tapestry.getString("service-requires-parameters", EXTERNAL_SERVICE));
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString("service-requires-parameters", Tapestry.EXTERNAL_SERVICE));
   
  -        String pageName = (String)parameters[0];
  +        String pageName = (String) parameters[0];
           String[] context = new String[] { pageName };
  -        
  +
           Object[] pageParameters = new Object[parameters.length - 1];
           System.arraycopy(parameters, 1, pageParameters, 0, parameters.length - 1);
   
  -        return assembleGesture(cycle, EXTERNAL_SERVICE, context, pageParameters, true);
  +        return assembleGesture(cycle, Tapestry.EXTERNAL_SERVICE, context, pageParameters, true);
       }
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws RequestCycleException, ServletException, IOException
       {
           IExternalPage page = null;
  @@ -168,10 +172,10 @@
   
           if (context == null || context.length != 1)
               throw new ApplicationRuntimeException(
  -                Tapestry.getString("service-single-context-parameter", EXTERNAL_SERVICE));
  +                Tapestry.getString("service-single-context-parameter", Tapestry.EXTERNAL_SERVICE));
   
           String pageName = context[0];
  -        
  +
           try
           {
               page = (IExternalPage) cycle.getPage(pageName);
  @@ -186,7 +190,7 @@
           Object[] parameters = getParameters(cycle);
   
           cycle.setServiceParameters(parameters);
  -        
  +
           page.validate(cycle);
           cycle.setPage(page);
   
  @@ -200,6 +204,6 @@
   
       public String getName()
       {
  -        return EXTERNAL_SERVICE;
  +        return Tapestry.EXTERNAL_SERVICE;
       }
   }
  
  
  
  1.4       +2 -2      jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/valid/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/valid/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	3 May 2002 20:03:06 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:34 -0000	1.4
  @@ -14,7 +14,7 @@
   is to add aliases for these components to the 
   application specification.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.3       +2 -1      jakarta-tapestry/doc/src/UsersGuide/TapestryUsersGuide.xml
  
  Index: TapestryUsersGuide.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/doc/src/UsersGuide/TapestryUsersGuide.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TapestryUsersGuide.xml	17 Jan 2003 17:38:44 -0000	1.2
  +++ TapestryUsersGuide.xml	24 Jan 2003 00:49:34 -0000	1.3
  @@ -39,6 +39,7 @@
   <!ENTITY spec.parameter '<link linkend="spec.parameter"><sgmltag class="starttag">parameter</sgmltag></link>'>
   <!ENTITY spec.private-asset '<link linkend="spec.private-asset"><sgmltag class="starttag">private-asset</sgmltag></link>'>
   <!ENTITY spec.property '<link linkend="spec.property"><sgmltag class="starttag">property</sgmltag></link>'>
  +<!ENTITY spec.property-specification '<link linkend="spec.property-specification"><sgmltag class="starttag">property-specification</sgmltag></link>'>
   <!ENTITY spec.reserved-parameter '<link linkend="spec.reserved-parameter"><sgmltag class="starttag">reserved-parameter</sgmltag></link>'>
   <!ENTITY spec.service '<link linkend="spec.service"><sgmltag class="starttag">service</sgmltag></link>'>
   <!ENTITY spec.set-property '<link linkend="spec.set-property"><sgmltag class="starttag">set-property</sgmltag></link>'>
  
  
  
  1.4       +82 -3     jakarta-tapestry/doc/src/UsersGuide/spec.xml
  
  Index: spec.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/doc/src/UsersGuide/spec.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- spec.xml	22 Jan 2003 16:51:19 -0000	1.3
  +++ spec.xml	24 Jan 2003 00:49:34 -0000	1.4
  @@ -601,7 +601,7 @@
   	<title><sgmltag class="starttag">component-specification</sgmltag> Elements</title>
   <literallayout>
     &spec.description; *, &spec.parameter; *, &spec.reserved-parameter; *, &spec.property; *,
  -  (&spec.bean; | &spec.component; | &spec.external-asset; | &spec.context-asset; | &spec.private-asset;)*
  +  (&spec.bean; | &spec.component; | &spec.external-asset; | &spec.context-asset; | &spec.private-asset; | &spec.property-specification;)*
   </literallayout>
   </figure>
   
  @@ -1169,7 +1169,7 @@
   	<title><sgmltag class="starttag">page-specification</sgmltag> Elements</title>
   <literallayout>
     &spec.description; *, &spec.property; *,
  -  (&spec.bean; | &spec.component; | &spec.external-asset; | &spec.context-asset; | &spec.private-asset;)*
  +  (&spec.bean; | &spec.component; | &spec.external-asset; | &spec.context-asset; | &spec.private-asset; | &spec.property-specification;)*
   </literallayout>
   </figure>
   
  @@ -1388,6 +1388,85 @@
   </informaltable>
   </figure>
   </section> <!-- spec.property -->
  +
  +
  +<section id="spec.property-specification">
  +	<title><sgmltag class="starttag">property-specification</sgmltag> element</title>
  +	
  +<para>
  +Appears in: &spec.component-specification;, &spec.page-specification;
  +</para>
  +
  +<para>
  +Defines a transient or persistent property to be added to the page or component.
  +Tapestry will create a subclass of the page or component class (at runtime)
  +and add the necessary fields and accessor methods, as well as end-of-request
  +cleanup.
  +</para>
  +
  +<para>
  +It is acceptible for a page (or component) to be abstract, and have abstract accessor methods
  +matching the names that Tapestry will generated for the subclass.  This can be
  +useful when setting properties of the page (or component) from a listener method.
  +</para>
  +
  +<figure>
  +	<title><sgmltag class="starttag">property-specification</sgmltag> Attributes</title>
  +<informaltable>
  +<tgroup cols="5">
  +<thead>
  +<row>
  +  <entry>Name</entry>
  +  <entry>Type</entry>
  +  <entry>Required ?</entry>
  +  <entry>Default Value</entry>
  +  <entry>Description</entry>
  +</row>
  +</thead>
  +<tbody>
  +<row>
  +	<entry>name</entry>
  +	<entry>string</entry>
  +	<entry>yes</entry>
  +	<entry/>
  +	<entry>The name of the property to create.</entry>
  +</row>
  +<row>
  +	<entry>type</entry>
  +	<entry>string</entry>
  +	<entry>no</entry>
  +	<entry>java.lang.Object</entry>
  +	<entry>
  +	The type of the property.  If abstract accessors exist, they must exactly match
  +	this type.  The type may be either a fully qualified class name, or the name
  +	of one of the basic scalar types.
  +	</entry>
  +</row>
  +<row>
  +	<entry>persistent</entry>
  +	<entry><literal>yes|no</literal></entry>
  +	<entry>no</entry>
  +	<entry><literal>no</literal></entry>
  +	<entry>
  +	If true, the generated property will be persistent, firing change notifications
  +	when it is updated.
  +	</entry>
  +</row>
  +<row>
  +	<entry>initial-value</entry>
  +	<entry>string</entry>
  +	<entry>no</entry>
  +	<entry/>
  +	<entry>
  +	An optional OGNL expression used to initialize the property.  The expression is evaluated
  +	only when the page is first constructed.
  +	</entry>
  +</row>
  +</tbody>
  +</tgroup>
  +</informaltable>
  +</figure>
  +</section> <!-- spec.property-specification -->
   
   <section id="spec.reserved-parameter">
   	<title><sgmltag class="starttag">reserved-parameter</sgmltag> element</title>
  
  
  
  1.3       +114 -25   jakarta-tapestry/doc/src/UsersGuide/state.xml
  
  Index: state.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/doc/src/UsersGuide/state.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- state.xml	17 Jan 2003 17:38:44 -0000	1.2
  +++ state.xml	24 Jan 2003 00:49:34 -0000	1.3
  @@ -19,12 +19,12 @@
   
   <para>
   Tapestry takes a different tack; it defines server-side state in terms of the Engine,
  -the Visit and persistant page properties.
  +the Visit and persistent page properties.
   </para>
   
   <para>
   The Engine is important because, ultimately, it is the lone object stored into the &HttpSession;.  Because it
  -is persistant, the Visit and all page properties are also persistant.
  +is persistent, the Visit and all page properties are also persistent.
   </para>
   
   <section id="state.visit">
  @@ -111,7 +111,7 @@
   </section> <!-- state.visit -->
   
   <section id="state.page-properties">
  -	<title>Pesistant Page Properties</title>
  +	<title>Persistent Page Properties</title>
   	
   <para>
   Servlets, and by extension, JavaServer Pages, are inherently stateless.  That is, they will be used
  @@ -124,7 +124,7 @@
   Instead, client-specific state and data must be stored in the &HttpSession; or as &HttpServletRequest; attributes.
   This is an awkward and limiting way to handle both <emphasis>transient</emphasis> state (state that is only needed
   during the actual processing of the request) and
  -<emphasis>persistant</emphasis> state (state that should be available during the processing of this
  +<emphasis>persistent</emphasis> state (state that should be available during the processing of this
   and subsequent requests).
   </para>
   
  @@ -147,12 +147,22 @@
   properties of the page that changed during the processing of the request must be returned to thier initial values.
   </para>
   
  +<note>
  +<para>
  +The following sections describe a scheme used through Tapestry release 2.3.  In release 2.4
  +<link linkend="state.declarative-properties">declarative properties</link> are used instead, since
  +they are much easier.
  +</para>
  +</note>
  +
   <para>
   The best way to do this is to implement the method <function>initialize()</function> on your page.  This method is invoked
   once when the page is first created; it is invoked again at the end of each request cycle.  An empty implementation
   of this method is provided by &AbstractPage;.
   </para>
   
  +
  +
   <example>
   	<title>Use of <function>initialize()</function> method</title>
   <programlisting>
  @@ -186,11 +196,11 @@
   
   <para>
   Now that we've shown how Tapestry allows pages to have <emphasis>transient</emphasis> state, we'll
  -show how to handle <emphasis>persistant</emphasis> state.
  +show how to handle <emphasis>persistent</emphasis> state.
   </para>	
   
   <para>
  -Tapestry separates the persistant state of a page from any instance.  This is very important, because
  +Tapestry separates the persistent state of a page from any instance.  This is very important, because
   from one request cycle to another, a different instance of the page may be used ... even when clustering is
   not used.  Again, Tapestry has many copies of any page in a pool, and pulls one instance out of the pool
   for each request.
  @@ -207,7 +217,7 @@
   </para>
   
   <para>
  -For a property to be persistant, all that's necessary is that the accessor method notify
  +For a property to be persistent, all that's necessary is that the accessor method notify
   the framework of changes.  Tapestry will record the changes (using an &IPageRecorder;)
   and, in later request cycles, will restore the property
   using using the recorded value and whichever page instance is taken out of the page pool.
  @@ -220,7 +230,7 @@
   </para>
   
   <example>
  -<title>Persistant Page Property</title>
  +<title>Persistent Page Property</title>
   <programlisting>
   public class MyPage extends &BasePage;
   {
  @@ -252,23 +262,11 @@
   the changed value will "stick" with the user who changed it, for the duration of their
   session.
   </para>
  -
  -<note id="state.page-properties.declarative">
  -<title>Coming in 2.4</title>
  -<para>
  -A feature planned for release 2.4, but not yet coded, is <emphasis>declarative properties</emphasis>.
  -This will allow the transient and persistant properties of a page (or component) to be
  -declared in the specification.  Tapestry will take care of everything else; this will likely
  -use some form of bytecode engineering; that is, Tapestry will create a subclass on the fly,
  -providing accessor methods, the <function>initialize()</function> method, possibly even
  -the instance variables themselves.
  -</para>
  -</note>
   	
   </section> <!-- state.page-properties -->
   
   <section id="state.component-properties">
  -	<title>Persistant Component Properties</title>
  +	<title>Persistent Component Properties</title>
   	
   <para>
   Transient and persistent properties are not limited just to pages.  The can be implemented
  @@ -296,7 +294,7 @@
   </para>
   
   <example>
  -	<title>Persistant Component Properties</title>
  +	<title>Persistent Component Properties</title>
   <programlisting>
   public class MyComponent extends &BaseComponent; implements &PageDetachListener;
   {
  @@ -339,6 +337,97 @@
   	
   </section> <!-- state.component-properties -->
   
  +<section id="state.declarative-properties">
  +	<title>Declarative Properties</title>
  +	
  +<para>
  +If all those extra methods are at all intimidating, don't fear, Tapestry provides another approach
  +to dealing with transient and persistent properties in pages and components: 
  +<emphasis>declarative properties</emphasis>.
  +</para>
  +
  +<para>
  +Declarative properties make use of a &spec.property-specification; element in the
  +page or component specification.  Tapestry does something special when a component
  +contains any such elements; it dynamically generates a subclass that provides the desired fields,
  +methods and whatever extra initialization or cleanup is required.
  +</para>
  +
  +<para>
  +You may also, optionally, make your class abstract, and define abstract accessor methods that will
  +be filled in by Tapestry in the generated subclass.  This allows you to read and update properties inside
  +your class, inside listener methods.
  +</para>
  +
  +<para>
  +Properties defined this way may be either transient or persistent.
  +</para>
  +
  +<para>
  +The previous example, of a persistent page property, can be reworked as the following:
  +</para>
  +	
  +<example>
  +<title>Declarative Persistent Page Property: Java Class</title>
  +<programlisting>
  +public abstract class MyPage extends &BasePage;
  +{
  +    abstract public int getItemsPerPage();
  +	
  +    abstract public void setItemsPerPage(int itemsPerPage);
  +}
  +</programlisting>
  +</example>	
  +
  +<example>
  +<title>Declarative Persistent Page Property: Page Specification</title>
  +<programlisting>
  +<![CDATA[
  +<?xml version="1.0" encoding="UTF-8"?>
  +<!DOCTYPE page-specification PUBLIC 
  +	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  +	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  +	
  +<page-specification class="MyPage">
  +
  +  <property-specification name="itemsPerPage" persistent="yes" type="int" initial-value="10"/>
  +
  +</page-specification>
  +]]>
  +</programlisting>
  +</example>	
  +
  +<para>
  +Again, making the class abstract, and defining abstract accessors is <emphasis>optional</emphasis>.
  +It is only useful when a listener method will need to update the property.
  +</para>
  +
  +<para>
  +This exact same technique can be used with components as well as pages, which vastly simplifies
  +the coding necessary, since it is not longer necessary to directly use
  +the &PageDetachListener; interface.
  +</para>
  +
  +<para>
  +A last note about initialization.  After Tapestry invokes the <function>finishLoad()</function>
  +method, it processes the initial value provided in the specification.  If 
  +the <literal>initial-value</literal> attribute is ommitted or blank, no change takes place.
  +Tapestry then takes a snapshot of the property value, which is retains 
  +and uses it at the end of each request cycle
  +to reset the property back to its "pristine" state.
  +</para>
  +
  +<para>
  +This means that you may perform initialization for the property inside
  +<function>finishLoad()</function> (instead of providing a <literal>initial-value</literal>).  However,
  +don't attempt to update the property from <function>initialize()</function> ... the order of operations
  +when the page detaches is not defined and is subject to change.
  +</para>
  +
  +
  +</section>  <!-- state.declarative-persistent-properties  -->
  +
  +
   <section id="state.stateless">
   	<title>Stateless Applications</title>
   	
  @@ -359,7 +448,7 @@
   
   <para>
   Tapestry defers creation of the &HttpSession; until one of two things happens:  When
  -the visit is created, or when the first persistant page property is recorded.  At this point,
  +the visit is created, or when the first persistent page property is recorded.  At this point,
   Tapestry will create the &HttpSession; and store the engine into it.
   </para>
   
  @@ -374,7 +463,7 @@
   <para>
   For the most part, your application will be unaware of when it is stateful or stateless; statefulness
   just happens on its own.  Ideally, at least the first, or "Home" page, should be stateless (it should be
  -organized in such a way that the visit is not created, and no persistant state is stored).  This will help
  +organized in such a way that the visit is not created, and no persistent state is stored).  This will help
   speed the initial display of the application, since no processing time will be used in creating the session.
   </para>	
   	
  
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Five.page
  
  Index: Five.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Five.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification class="net.sf.tapestry.junit.mock.c9.Five">
  
    <property-specification name="word" type="java.lang.String"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ "Tempest", "Pac-Man", "Diamond Mine" }
    	</binding>
    	<binding name="value" expression="word"/>
    </component>
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Two.page
  
  Index: Two.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Two.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification>
  
    <property-specification name="number" type="int" initial-value="15"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ 2, 4, 6, 8 }
    	</binding>
    	<binding name="value" expression="number"/>
    </component>
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Home.page
  
  Index: Home.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Home.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification>
  
    <property-specification name="word" type="java.lang.String"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ "Gromit", "is", "a", "good", "boy" }
    	</binding>
    	<binding name="value" expression="word"/>
    </component>
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Four.page
  
  Index: Four.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Four.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification class="net.sf.tapestry.junit.mock.c9.Four">
  
    <property-specification name="word" type="java.lang.String"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ "Soul", "Calibur" }
    	</binding>
    	<binding name="value" expression="word"/>
    </component>
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Six.page
  
  Index: Six.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Six.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification class="net.sf.tapestry.junit.mock.c9.Six">
  
    <property-specification name="value" type="long" initial-value="15"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ 2, 4, 6, 8 }
    	</binding>
    	<binding name="value" expression="value"/>
    </component>
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Seven.page
  
  Index: Seven.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Seven.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification class="net.sf.tapestry.junit.mock.c9.Seven">
  
    <property-specification name="booleanValue" type="boolean" persistent="yes"/>
    <property-specification name="byteValue" type="byte" persistent="yes"/>
    <property-specification name="charValue" type="char" persistent="yes"/>
    <property-specification name="shortValue" type="short" persistent="yes"/>
    <property-specification name="intValue" type="int" persistent="yes"/>
    <property-specification name="longValue" type="long" persistent="yes"/>
    <property-specification name="floatValue" type="float" persistent="yes"/>
    <property-specification name="doubleValue" type="double" persistent="yes"/>
    <property-specification name="stringValue" type="java.lang.String" persistent="yes"/>
    
  
  </page-specification>
  
  
  1.1                  jakarta-tapestry/junit/Context9/WEB-INF/Three.page
  
  Index: Three.page
  ===================================================================
  <?xml version="1.0" encoding="UTF-8"?>
  <!-- $Id: Three.page,v 1.1 2003/01/24 00:49:34 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
  	
  <page-specification class="net.sf.tapestry.junit.mock.c9.Three">
  
    <property-specification name="word" type="java.lang.String"/>
    
    <component id="loop" type="Foreach">
    	<static-binding name="element" value="li"/>
    	<binding name="source">
    		{ "Crazy", "Taxi" }
    	</binding>
    	<binding name="value" expression="word"/>
    </component>
  
  </page-specification>
  
  
  1.13      +14 -13    jakarta-tapestry/framework/src/net/sf/tapestry/Gesture.java
  
  Index: Gesture.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/Gesture.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Gesture.java	13 Jan 2003 03:33:08 -0000	1.12
  +++ Gesture.java	24 Jan 2003 00:49:34 -0000	1.13
  @@ -194,7 +194,7 @@
       {
           StringBuffer buffer = new StringBuffer();
           RequestContext context = _cycle.getRequestContext();
  - 
  +
           if (scheme == null)
               scheme = context.getScheme();
   
  @@ -228,14 +228,14 @@
           if (includeParameters)
           {
               buffer.append('?');
  -            buffer.append(IEngineService.SERVICE_QUERY_PARAMETER_NAME);
  +            buffer.append(Tapestry.SERVICE_QUERY_PARAMETER_NAME);
               buffer.append('=');
               buffer.append(_serviceName);
   
               if (_serviceContext != null)
               {
                   buffer.append('&');
  -                buffer.append(IEngineService.CONTEXT_QUERY_PARMETER_NAME);
  +                buffer.append(Tapestry.CONTEXT_QUERY_PARMETER_NAME);
                   buffer.append('=');
                   buffer.append(_serviceContext);
               }
  @@ -246,7 +246,7 @@
               {
                   buffer.append('&');
   
  -                buffer.append(IEngineService.PARAMETERS_QUERY_PARAMETER_NAME);
  +                buffer.append(Tapestry.PARAMETERS_QUERY_PARAMETER_NAME);
                   buffer.append('=');
   
                   try
  @@ -289,13 +289,13 @@
       {
           List list = new ArrayList();
   
  -        list.add(IEngineService.SERVICE_QUERY_PARAMETER_NAME);
  +        list.add(Tapestry.SERVICE_QUERY_PARAMETER_NAME);
   
           if (_serviceContext != null)
  -            list.add(IEngineService.CONTEXT_QUERY_PARMETER_NAME);
  +            list.add(Tapestry.CONTEXT_QUERY_PARMETER_NAME);
   
           if (Tapestry.size(_serviceParameters) != 0)
  -            list.add(IEngineService.PARAMETERS_QUERY_PARAMETER_NAME);
  +            list.add(Tapestry.PARAMETERS_QUERY_PARAMETER_NAME);
   
           return (String[]) list.toArray(new String[list.size()]);
       }
  @@ -311,22 +311,23 @@
   
       public String[] getParameterValues(String name)
       {
  -        if (name.equals(IEngineService.SERVICE_QUERY_PARAMETER_NAME))
  +        if (name.equals(Tapestry.SERVICE_QUERY_PARAMETER_NAME))
           {
               return new String[] { _serviceName };
           }
  -        
  -        if (name.equals(IEngineService.CONTEXT_QUERY_PARMETER_NAME))
  +
  +        if (name.equals(Tapestry.CONTEXT_QUERY_PARMETER_NAME))
           {
               return new String[] { _serviceContext };
           }
   
  -        if (name.equals(IEngineService.PARAMETERS_QUERY_PARAMETER_NAME))
  +        if (name.equals(Tapestry.PARAMETERS_QUERY_PARAMETER_NAME))
           {
               return _serviceParameters;
           }
   
  -        throw new IllegalArgumentException(Tapestry.getString("Gesture.unknown-parameter-name", name));
  +        throw new IllegalArgumentException(
  +            Tapestry.getString("Gesture.unknown-parameter-name", name));
   
       }
   
  
  
  
  1.40      +18 -1     jakarta-tapestry/framework/src/net/sf/tapestry/TapestryStrings.properties
  
  Index: TapestryStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/TapestryStrings.properties,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- TapestryStrings.properties	17 Jan 2003 17:40:17 -0000	1.39
  +++ TapestryStrings.properties	24 Jan 2003 00:49:34 -0000	1.40
  @@ -131,6 +131,8 @@
   AbstractEngine.unable-to-find-dispatcher=Unable to find a request dispatcher for local resource ''{0}''.
   AbstractEngine.unable-to-forward=Unable to forward to local resource ''{0}''.
   AbstractEngine.unable-to-create-cleanup-context=Unable to create an instance of RequestContext to process end-of-session page cleanups.
  +AbstractEngine.exception-during-cleanup=Exception during post-request cleanup.
  +AbstractEngine.exception-during-cache-clear=Exception while clearing caches after request.
   
   ActionService.context-parameters=Service action requires either three or four service contect parameters.
   ActionService.action-component-wrong-type=Component {0} dopes not implement the IAction interface.
  @@ -169,6 +171,16 @@
   
   ExternalService.page-not-compatible=Page {0} does not implement the IExternalPage interface.
   
  +# net.sf.tapestry.enhance
  +
  +DefaultComponentClassEnhancer.property-type-mismatch=Unable to enhance class {0} because it contains property ''{1}'' of type {2}, not the expected type {3}.
  +DefaultComponentClassEnhancer.non-abstract-read=Unable to enhance class {0} because it implements a non-abstract read method for property ''{1}''.
  +DefaultComponentClassEnhancer.non-abstract-write=Unable to enhance class {0} because it implements a non-abstract write method for property ''{1}''.
  +DefaultComponentClassEnhancer.unable-to-introspect-class=Unable to introspect properties of class {0}.
  +
  +EnhancedClassLoader.unable-to-define-class=Unable to define class {0}: {1}
  +
  +MethodFabricator.no-more-arguments=No more arguments may be added once any local variables are added.
   
   # net.sf.tapestry.event
   
  @@ -335,6 +347,7 @@
   ComponentSpecification.duplicate-component={0}: already contains component ''{1}''.
   ComponentSpecification.duplicate-parameter={0}: already contains parameter ''{1}''.
   ComponentSpecification.duplicate-bean={0}: already contains bean definition for ''{1}''.
  +ComponentSpecification.duplicate-property-specification={0}: already contains property specification for property ''{1}''.
   
   ExtensionSpecification.duplicate-property={0}: already contains property configuration for ''{1}''.
   
  @@ -374,6 +387,10 @@
   # net.sf.tapestry.util.prop
   
   PropertyFinder.unable-to-introspect-class=Unable to instrospect properties of class {0}.
  +
  +OgnlUtils.unable-to-update-expression=Unable to update expression ''{0}'' of {1} to {2}.
  +OgnlUtils.unable-to-read-expression=Unable to read expression ''{0}'' of {1}.
  +OgnlUtils.unable-to-parse-expression=Unable to parse expression ''{0}''.
   
   # net.sf.tapestry.util.xml
   
  
  
  
  1.17      +12 -1     jakarta-tapestry/framework/src/net/sf/tapestry/IEngine.java
  
  Index: IEngine.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/IEngine.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- IEngine.java	17 Jan 2003 17:40:17 -0000	1.16
  +++ IEngine.java	24 Jan 2003 00:49:34 -0000	1.17
  @@ -400,6 +400,7 @@
        **/
   
       public IPropertySource getPropertySource();
  +    
       /**
        *  Returns a {@link net.sf.tapestry.util.pool.Pool} that is used
        *  to store all manner of objects that are needed throughout the system.
  @@ -413,4 +414,14 @@
        **/
       
       public Pool getPool();
  +    
  +    /**
  +     *  Returns an object that can create enhanced versions of component classes.
  +     * 
  +     *  @since 2.4
  +     *  @see net.sf.tapestry.engine.AbstractEngine#createComponentClassEnhancer(RequestContext)
  +     * 
  +     **/
  +    
  +    public IComponentClassEnhancer getComponentClassEnhancer();
   }
  
  
  
  1.13      +131 -2    jakarta-tapestry/framework/src/net/sf/tapestry/Tapestry.java
  
  Index: Tapestry.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/Tapestry.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Tapestry.java	22 Jan 2003 16:50:59 -0000	1.12
  +++ Tapestry.java	24 Jan 2003 00:49:34 -0000	1.13
  @@ -78,7 +78,8 @@
   import net.sf.tapestry.util.StringSplitter;
   
   /**
  - *  A placeholder for a number of (static) methods that don't belong elsewhere.
  + *  A placeholder for a number of (static) methods that don't belong elsewhere, as well
  + *  as a global location for static constants.
    *
    *  @since 1.0.1
    *  @version $Id$
  @@ -88,6 +89,134 @@
   
   public final class Tapestry
   {
  +	/**
  +	 *  The name ("action") of a service that allows behavior to be associated with
  +	 *  an {@link IAction} component, such as {@link ActionLink} or {@link Form}.
  +	 *  
  +	 *  <p>This service is used with actions that are tied to the
  +	 *  dynamic state of the page, and which require a rewind of the page.
  +	 *
  +	 **/
  +
  +	public final static String ACTION_SERVICE = "action";
  +
  +	/**
  +	 *  The name ("direct") of a service that allows stateless behavior for an {@link
  +	 *  DirectLink} component.
  +	 *
  +	 *  <p>This service rolls back the state of the page but doesn't
  +	 *  rewind the the dynamic state of the page the was the action
  +	 *  service does, which is more efficient but less powerful.
  +	 *
  +	 *  <p>An array of String parameters may be included with the
  +	 *  service URL; these will be made available to the {@link DirectLink}
  +	 *  component's listener.
  +	 *
  +	 **/
  +
  +	public final static String DIRECT_SERVICE = "direct";
  +
  +    /**
  +     *  The name ("external") of a service that a allows {@link IExternalPage} to be selected.
  +     *  Associated with a {@link ExternalLink} component.
  +     *
  +     *  <p>This service enables {@link IExternalPage}s to be accessed via a URL.
  +     *  External pages may be booked marked using their URL for future reference.
  +     *
  +     *  <p>An array of Object parameters may be included with the
  +     *  service URL; these will be passed to the 
  +     *  {@link IExternalPage#activateExternalPage(Object[], IRequestCycle)} method.
  +     *
  +     **/
  +
  +    public final static String EXTERNAL_SERVICE = "external";
  +
  +	/**
  +	 *  The name ("page") of a service that allows a new page to be selected.
  +	 *  Associated with a {@link PageLink} component.
  +	 *
  +	 *  <p>The service requires a single parameter:  the name of the target page.
  +	 **/
  +
  +	public final static String PAGE_SERVICE = "page";
  +
  +	/**
  +	 *  The name ("home") of a service that jumps to the home page.  A stand-in for
  +	 *  when no service is provided, which is typically the entrypoint
  +	 *  to the application.
  +	 *
  +	 **/
  +
  +	public final static String HOME_SERVICE = "home";
  +
  +	/**
  +	 *  The name ("restart") of a service that invalidates the session and restarts
  +	 *  the application.  Typically used just
  +	 *  to recover from an exception.
  +	 *
  +	 **/
  +
  +	public static final String RESTART_SERVICE = "restart";
  +
  +	/**
  +	 *  The name ("asset") of a service used to access internal assets.
  +	 *
  +	 **/
  +
  +	public static final String ASSET_SERVICE = "asset";
  +
  +	/**
  +	 *  The name ("reset") of a service used to clear cached template
  +	 *  and specification data and remove all pooled pages.
  +	 *  This is only used when debugging as
  +	 *  a quick way to clear the out cached data, to allow updated
  +	 *  versions of specifications and templates to be loaded (without
  +	 *  stopping and restarting the servlet container).
  +	 *
  +	 *  <p>This service is only available if the Java system property
  +	 *  <code>net.sf.tapestry.enable-reset-service</code>
  +	 *  is set to <code>true</code>.
  +	 * 
  +	 **/
  +
  +	public static final String RESET_SERVICE = "reset";
  +
  +	/**
  +	 *  Query parameter that identfies the service for the
  +     *  request.
  +	 *
  +	 *  @since 1.0.3
  +     * 
  +	 **/
  +
  +	public static final String SERVICE_QUERY_PARAMETER_NAME = "service";
  +
  +	/**
  +	 *  The query parameter for additional context needed by the
  +	 *  service.  This is used to store things like the page name or component id.
  +	 *  When there are multiple pieces of data, they are seperated by
  +	 *  slashes.  Not all services use a context.
  +	 *
  +	 *  @since 1.0.3
  + 	 *
  +	 **/
  +
  +	public static final String CONTEXT_QUERY_PARMETER_NAME = "context";
  +
  +	/**
  +	 *  The query parameter for application specific parameters to the
  +	 *  service (this is used with the direct service).  Each of these
  +	 *  values is encoded with {@link java.net.URLEncoder#encode(String)} before
  +	 *  being added to the URL.  Multiple values are handle by repeatedly
  +     *  establishing key/value pairs (this is a change from behavior in 
  +     *  2.1 and earlier).
  +	 *
  +	 *  @since 1.0.3
  +     * 
  +	 **/
  +
  +	public static final String PARAMETERS_QUERY_PARAMETER_NAME = "sp";
  +		
   	/**
   	 *  Property name used to get the extension used for templates.  This
   	 *  may be set in the page or component specification, or in the page (or
  
  
  
  1.14      +115 -169  jakarta-tapestry/framework/src/net/sf/tapestry/IEngineService.java
  
  Index: IEngineService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/IEngineService.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- IEngineService.java	13 Jan 2003 03:33:08 -0000	1.13
  +++ IEngineService.java	24 Jan 2003 00:49:34 -0000	1.14
  @@ -74,183 +74,129 @@
   
   public interface IEngineService
   {
  -	/**
  -	 *  The name ("action") of a service that allows behavior to be associated with
  -	 *  an {@link IAction} component, such as {@link ActionLink} or {@link Form}.
  -	 *  
  -	 *  <p>This service is used with actions that are tied to the
  -	 *  dynamic state of the page, and which require a rewind of the page.
  -	 *
  -	 **/
  -
  -	public final static String ACTION_SERVICE = "action";
  -
  -	/**
  -	 *  The name ("direct") of a service that allows stateless behavior for an {@link
  -	 *  DirectLink} component.
  -	 *
  -	 *  <p>This service rolls back the state of the page but doesn't
  -	 *  rewind the the dynamic state of the page the was the action
  -	 *  service does, which is more efficient but less powerful.
  -	 *
  -	 *  <p>An array of String parameters may be included with the
  -	 *  service URL; these will be made available to the {@link DirectLink}
  -	 *  component's listener.
  -	 *
  -	 **/
  -
  -	public final static String DIRECT_SERVICE = "direct";
  -
  -    /**
  -     *  The name ("external") of a service that a allows {@link IExternalPage} to be selected.
  -     *  Associated with a {@link ExternalLink} component.
  -     *
  -     *  <p>This service enables {@link IExternalPage}s to be accessed via a URL.
  -     *  External pages may be booked marked using their URL for future reference.
  -     *
  -     *  <p>An array of Object parameters may be included with the
  -     *  service URL; these will be passed to the 
  -     *  {@link IExternalPage#activateExternalPage(Object[], IRequestCycle)} method.
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#ACTION_SERVICE} instead.
  +     *
  +     **/
  +
  +    public final static String ACTION_SERVICE = "action";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#DIRECT_SERVICE} instead.
  +     *
  +     **/
  +
  +    public final static String DIRECT_SERVICE = "direct";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#EXTERNAL_SERVICE} instead.
        *
        **/
   
       public final static String EXTERNAL_SERVICE = "external";
   
  -	/**
  -	 *  The name ("page") of a service that allows a new page to be selected.
  -	 *  Associated with a {@link PageLink} component.
  -	 *
  -	 *  <p>The service requires a single parameter:  the name of the target page.
  -	 **/
  -
  -	public final static String PAGE_SERVICE = "page";
  -
  -	/**
  -	 *  The name ("home") of a service that jumps to the home page.  A stand-in for
  -	 *  when no service is provided, which is typically the entrypoint
  -	 *  to the application.
  -	 *
  -	 **/
  -
  -	public final static String HOME_SERVICE = "home";
  -
  -	/**
  -	 *  The name ("restart") of a service that invalidates the session and restarts
  -	 *  the application.  Typically used just
  -	 *  to recover from an exception.
  -	 *
  -	 **/
  -
  -	public static final String RESTART_SERVICE = "restart";
  -
  -	/**
  -	 *  The name ("asset") of a service used to access internal assets.
  -	 *
  -	 **/
  -
  -	public static final String ASSET_SERVICE = "asset";
  -
  -	/**
  -	 *  The name ("reset") of a service used to clear cached template
  -	 *  and specification data and remove all pooled pages.
  -	 *  This is only used when debugging as
  -	 *  a quick way to clear the out cached data, to allow updated
  -	 *  versions of specifications and templates to be loaded (without
  -	 *  stopping and restarting the servlet container).
  -	 *
  -	 * <p>This service is only available if the Java system property
  -	 *  <code>net.sf.tapestry.enable-reset-service</code>
  -	 *  is set to <code>true</code>.
  -	 **/
  -
  -	public static final String RESET_SERVICE = "reset";
  -
  -	/**
  -	 *  Query parameter that identfies the service for the
  -     *  request.
  -	 *
  -	 *  @since 1.0.3
  -     * 
  -	 **/
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#PAGE_SERVICE} instead.
  +     *
  +     **/
   
  -	public static final String SERVICE_QUERY_PARAMETER_NAME = "service";
  +    public final static String PAGE_SERVICE = "page";
   
  -	/**
  -	 *  The query parameter for additional context needed by the
  -	 *  service.  This is used to store things like the page name or component id.
  -	 *  When there are multiple pieces of data, they are seperated by
  -	 *  slashes.  Not all services use a context.
  -	 *
  -	 *  @since 1.0.3
  - 	 *
  -	 **/
  -
  -	public static final String CONTEXT_QUERY_PARMETER_NAME = "context";
  -
  -	/**
  -	 *  The query parameter for application specific parameters to the
  -	 *  service (this is used with the direct service).  Each of these
  -	 *  values is encoded with {@link java.net.URLEncoder#encode(String)} before
  -	 *  being added to the URL.  Multiple values are handle by repeatedly
  -     *  establishing key/value pairs (this is a change from behavior in 
  -     *  2.1 and earlier).
  -	 *
  -	 *  @since 1.0.3
  -     * 
  -	 **/
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#HOME_SERVICE} instead.
  +     *
  +     **/
  +
  +    public final static String HOME_SERVICE = "home";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#RESTART_SERVICE} instead.
  +     *
  +     **/
  +
  +    public static final String RESTART_SERVICE = "restart";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#ASSET_SERVICE} instead.
  +     *
  +     **/
  +
  +    public static final String ASSET_SERVICE = "asset";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#RESET_SERVICE} instead.
  +     *
  +     **/
  +
  +    public static final String RESET_SERVICE = "reset";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use 
  +     *  {@link Tapestry#SERVICE_QUERY_PARAMETER_NAME} instead.
  +     *
  +     **/
  +
  +    public static final String SERVICE_QUERY_PARAMETER_NAME = "service";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use {@link Tapestry#CONTEXT_QUERY_PARMETER_NAME} instead.
  +     *
  +     **/
  +
  +    public static final String CONTEXT_QUERY_PARMETER_NAME = "context";
  +
  +    /**
  +     *  @deprecated To be removed in 2.5.  Use 
  +     *  {@link Tapestry#PARAMETERS_QUERY_PARAMETER_NAME} instead.
  +     *
  +     **/
  +
  +    public static final String PARAMETERS_QUERY_PARAMETER_NAME = "sp";
  +
  +    /**
  +     *  Builds a URL for a service.  This is performed during the
  +     *  rendering phase of one request cycle and bulds URLs that will
  +     *  invoke activity in a subsequent request cycle.
  +     *
  +     *  @param cycle Defines the request cycle being processed.
  +     *  @param component The component requesting the URL.  Generally, the
  +     *  service context is established from the component.
  +     *  @param parameters Additional parameters specific to the
  +     *  component requesting the Gesture.
  +     *  @return The URL for the service.  The URL will have to be encoded
  +     *  via {@link HttpServletResponse#encodeURL(java.lang.String)}.
  +     *
  +     **/
   
  -	public static final String PARAMETERS_QUERY_PARAMETER_NAME = "sp";
  +    public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters);
   
  -	/**
  -	 *  Builds a URL for a service.  This is performed during the
  -	 *  rendering phase of one request cycle and bulds URLs that will
  -	 *  invoke activity in a subsequent request cycle.
  +    /**
  +     *  Perform the service, interpreting the URL (from the
  +     *  {@link javax.servlet.http.HttpServletRequest}) 
  +     *  responding appropriately, and
  +     *  rendering a result page.
  +     *
  +     *  <p>The return value indicates whether processing of the request could, in any way,
  +     *  change the state of the {@link IEngine engine}.  Generally, this is true.
  +     *
  +     *  @see IEngine#service(RequestContext)
  +     *  @param engine a view of the {@link IEngine} with additional methods needed by services
  +     *  @param cycle the incoming request
  +     *  @param output stream to which output should ultimately be directed
        * 
  -     *  <p><b>Through release 2.1, parameters was String[],
  -     *  not Object[].  This is an incompatible change.</b>
  -	 *
  -	 *  @param cycle Defines the request cycle being processed.
  -	 *  @param component The component requesting the URL.  Generally, the
  -	 *  service context is established from the component.
  -	 *  @param parameters Additional parameters specific to the
  -	 *  component requesting the Gesture.
  -	 *  @return The URL for the service.  The URL will have to be encoded
  -	 *  via {@link HttpServletResponse#encodeURL(java.lang.String)}.
  -	 *
  -	 **/
  -
  -	public Gesture buildGesture(
  -		IRequestCycle cycle,
  -		IComponent component,
  -		Object[] parameters);
  -
  -	/**
  -	 *  Perform the service, interpreting the URL (from the
  -	 *  {@link javax.servlet.http.HttpServletRequest}) 
  -	 *  responding appropriately, and
  -	 *  rendering a result page.
  -	 *
  -	 *  <p>The return value indicates whether processing of the request could, in any way,
  -	 *  change the state of the {@link IEngine engine}.  Generally, this is true.
  -	 *
  -	 *  @see IEngine#service(RequestContext)
  -	 *  @param engine a view of the {@link IEngine} with additional methods needed by services
  -	 *  @param cycle the incoming request
  -	 *  @param output stream to which output should ultimately be directed
  -	 * 
  -	 **/
  -
  - 	public boolean service(
  -		IEngineServiceView engine,
  -		IRequestCycle cycle,
  -		ResponseOutputStream output)
  -		throws RequestCycleException, ServletException, IOException;
  -
  -	/**
  -	 *  Returns the name of the service.
  -	 *
  -	 *  @since 1.0.1
  -	 **/
  +     **/
  +
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
  +        throws RequestCycleException, ServletException, IOException;
  +
  +    /**
  +     *  Returns the name of the service.
  +     *
  +     *  @since 1.0.1
  +     **/
   
  -	public String getName();
  +    public String getName();
   }
  
  
  
  1.16      +8 -8      jakarta-tapestry/framework/src/net/sf/tapestry/AbstractPage.java
  
  Index: AbstractPage.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/AbstractPage.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- AbstractPage.java	17 Jan 2003 17:40:17 -0000	1.15
  +++ AbstractPage.java	24 Jan 2003 00:49:34 -0000	1.16
  @@ -176,9 +176,10 @@
       /**
        *  Prepares the page to be returned to the pool.
        *  <ul>
  +     *  <li>Clears the changeObserved property
        *	<li>Invokes {@link PageDetachListener#pageDetached(PageEvent)} on all listeners
        *  <li>Invokes {@link #initialize()} to clear/reset any properties	
  -     * <li>Clears the engine, visit and changeObserver properties
  +     * <li>Clears the engine, visit and requestCycle properties
        *	</ul>
        *
        *  <p>Subclasses may override this method, but must invoke this
  @@ -188,13 +189,17 @@
   
       public void detach()
       {
  +    	// Do this first,so that any changes to persistent properties do not
  +    	// cause errors.
  +    	
  +        _changeObserver = null;
  +
           firePageDetached();
   
           initialize();
   
           _engine = null;
           _visit = null;
  -        _changeObserver = null;
           _requestCycle = null;
       }
   
  @@ -269,11 +274,6 @@
       public String getName()
       {
           return _name;
  -    }
  -
  -    public IPage getPage()
  -    {
  -        return this;
       }
   
       public IComponent getNestedComponent(String path)
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	5 May 2002 21:04:00 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:34 -0000	1.2
  @@ -44,7 +44,7 @@
   <a href="http://sourceforge.net/projects/tapestry">http://sourceforge.net/projects/tapestry</a>
   for more details on licensing.
   
  -@author Howard Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/IComponentClassEnhancer.java
  
  Index: IComponentClassEnhancer.java
  ===================================================================
  package net.sf.tapestry;
  
  import net.sf.tapestry.spec.ComponentSpecification;
  
  /**
   *
   *  A provider of enhanced classes, classes with new methods 
   *  and new attributes, and possibly, implementing new
   *  Java interfaces.  The primary use of class enhancement is to
   *  automate the creation of transient and persistant properties.
   * 
   *  <p>
   *  Implementations of this interface must be threadsafe.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: IComponentClassEnhancer.java,v 1.1 2003/01/24 00:49:34 hlship Exp $
   *  @since 2.4
   * 
   **/
  
  public interface IComponentClassEnhancer
  {
  	/**
  	 *  Clears all cached data for the enhancer; this includes references to
  	 *  enhanced classes.
  	 * 
  	 **/
  	
  	public void reset();
  	
  	/**
  	 *  Used to access the class for a given component (or page).  Returns the
  	 *  specified class, or an enhanced version of the class if the
  	 *  component requires enhancement.
  	 * 
  	 *  @param specification the specification for the component
  	 *  @param className the name of base class to enhance, as extracted
  	 *  from the specification (or possibly, from a default).
  	 * 
  	 *  @throws ApplicationRuntimeException if the class does not exist, is invalid,
  	 *  or may not be enhanced.
  	 * 
  	 **/
  	
  	public Class getEnhancedClass(ComponentSpecification specification, String className);
  }
  
  
  
  1.2       +2 -2      jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/ejb/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/ejb/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	12 Oct 2002 17:28:07 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:35 -0000	1.2
  @@ -10,7 +10,7 @@
   to identify the underlying reason for the exception.  This is less necessary in JDK 1.4, which
   support root cause for all exceptions.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.15      +12 -0     jakarta-tapestry/framework/src/net/sf/tapestry/spec/SpecFactory.java
  
  Index: SpecFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/spec/SpecFactory.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- SpecFactory.java	17 Jan 2003 17:40:20 -0000	1.14
  +++ SpecFactory.java	24 Jan 2003 00:49:35 -0000	1.15
  @@ -240,4 +240,16 @@
       {
           return new ExtensionSpecification();
       }
  +    
  +    /**
  +     *  Creates a concrete instance of {@link net.sf.tapestry.spec.PropertySpecification}.
  +     * 
  +     *  @since 2.4
  +     * 
  +     **/
  +    
  +    public PropertySpecification createPropertySpecification()
  +    {
  +    	return new PropertySpecification();
  +    }
   }
  
  
  
  1.14      +88 -25    jakarta-tapestry/framework/src/net/sf/tapestry/spec/ComponentSpecification.java
  
  Index: ComponentSpecification.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/spec/ComponentSpecification.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- ComponentSpecification.java	17 Jan 2003 17:40:20 -0000	1.13
  +++ ComponentSpecification.java	24 Jan 2003 00:49:35 -0000	1.14
  @@ -101,9 +101,9 @@
   public class ComponentSpecification extends BasePropertyHolder
   {
       private String _componentClassName;
  -    
  +
       /** @since 1.0.9 **/
  -    
  +
       private String _description;
   
       /**
  @@ -180,17 +180,26 @@
   
       private boolean _pageSpecification;
   
  -
       /**
        *  The location from which the specification was obtained.
        * 
        *  @since 2.4
        * 
        **/
  -    
  +
       private IResourceLocation _specificationLocation;
   
       /**
  +     *  A Map of {@link PropertySpecification} keyed on the name
  +     *  of the property.
  +     *
  +     *  @since 2.4
  +     * 
  +     **/
  +
  +    private Map _propertySpecifications;
  +
  +    /**
        * @throws IllegalArgumentException if the name already exists.
        *
        **/
  @@ -283,10 +292,8 @@
   
       public AssetSpecification getAsset(String name)
       {
  -        if (_assets == null)
  -            return null;
   
  -        return (AssetSpecification) _assets.get(name);
  +        return (AssetSpecification) get(_assets, name);
       }
   
       /**
  @@ -311,10 +318,7 @@
   
       public ContainedComponent getComponent(String id)
       {
  -        if (_components == null)
  -            return null;
  -
  -        return (ContainedComponent) _components.get(id);
  +        return (ContainedComponent) get(_components, id);
       }
   
       public String getComponentClassName()
  @@ -346,10 +350,7 @@
   
       public ParameterSpecification getParameter(String name)
       {
  -        if (_parameters == null)
  -            return null;
  -
  -        return (ParameterSpecification) _parameters.get(name);
  +        return (ParameterSpecification) get(_parameters, name);
       }
   
       /**
  @@ -366,7 +367,6 @@
           return sortedKeys(_parameters);
       }
   
  -
       public void setAllowBody(boolean value)
       {
           _allowBody = value;
  @@ -382,7 +382,6 @@
           _componentClassName = value;
       }
   
  -
       /**
        *  @since 1.0.4
        *
  @@ -394,8 +393,10 @@
           if (_beans == null)
               _beans = new HashMap();
   
  -        else if (_beans.containsKey(name))
  -            throw new IllegalArgumentException(Tapestry.getString("ComponentSpecification.duplicate-bean", this, name));
  +        else
  +            if (_beans.containsKey(name))
  +                throw new IllegalArgumentException(
  +                    Tapestry.getString("ComponentSpecification.duplicate-bean", this, name));
   
           _beans.put(name, specification);
       }
  @@ -469,13 +470,13 @@
       public String toString()
       {
           ToStringBuilder builder = new ToStringBuilder(this);
  -        
  +
           builder.append("componentClassName", _componentClassName);
           builder.append("pageSpecification", _pageSpecification);
           builder.append("specificationLocation", _specificationLocation);
           builder.append("allowBody", _allowBody);
           builder.append("allowInformalParameter", _allowInformalParameters);
  -        
  +
           return builder.toString();
       }
   
  @@ -564,19 +565,81 @@
   
           return result;
       }
  -    
  +
  +    /** @since 2.2 **/
  +
  +    private Object get(Map map, Object key)
  +    {
  +        if (map == null)
  +            return null;
  +
  +        return map.get(key);
  +    }
  +
       /** @since 2.4 **/
  -    
  +
       public IResourceLocation getSpecificationLocation()
       {
           return _specificationLocation;
       }
   
       /** @since 2.4 **/
  -    
  +
       public void setSpecificationLocation(IResourceLocation specificationLocation)
       {
           _specificationLocation = specificationLocation;
  +    }
  +
  +    /**
  +     *  Adds a new property specification.  The name of the property must
  +     *  not already be defined (and must not change after being added).
  +     * 
  +     *  @since 2.4
  +     * 
  +     **/
  +
  +    public void addPropertySpecification(PropertySpecification spec)
  +    {
  +        if (_propertySpecifications == null)
  +            _propertySpecifications = new HashMap();
  +
  +        String name = spec.getName();
  +
  +        if (_propertySpecifications.containsKey(name))
  +            throw new IllegalArgumentException(
  +                Tapestry.getString(
  +                    "ComponentSpecification.duplicate-property-specification",
  +                    this,
  +                    name));
  +
  +        _propertySpecifications.put(name, spec);
  +    }
  +
  +    /**
  +     *  Returns a sorted, immutable list of the names of all 
  +     *  {@link net.sf.tapestry.spec.PropertySpecification}s.
  +     * 
  +     *  @since 2.4
  +     * 
  +     **/
  +
  +    public List getPropertySpecificationNames()
  +    {
  +        return sortedKeys(_propertySpecifications);
  +    }
  +
  +    /**
  +     *  Returns the named {@link net.sf.tapestry.spec.PropertySpecification},
  +     *  or null  if no such specification exist.
  +     * 
  +     *  @since 2.4
  +     *  @see #addPropertySpecification(PropertySpecification)
  +     * 
  +     **/
  +
  +    public PropertySpecification getPropertySpecification(String name)
  +    {
  +        return (PropertySpecification) get(_propertySpecifications, name);
       }
   
   }
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/spec/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/spec/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:53:09 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:35 -0000	1.4
  @@ -8,7 +8,7 @@
   
   <p>Classes to represent application and component specifications.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/spec/PropertySpecification.java
  
  Index: PropertySpecification.java
  ===================================================================
  package net.sf.tapestry.spec;
  /**
   *  Defines a transient or persistant property of a component or page.  
   *  A {@link net.sf.tapestry.IComponentClassEnhancer} uses this information
   *  to create a subclass with the necessary instance variables and methods.  
   *
   *  @author Howard Lewis Ship
   *  @version $Id: PropertySpecification.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   * 
   **/
  
  public class PropertySpecification
  {
  	private String _name;
  	private String _type = "java.lang.Object";
  	private boolean _persistent;
  	private String _initialValue;
  	
      public String getInitialValue()
      {
          return _initialValue;
      }
  
      public String getName()
      {
          return _name;
      }
  
      public boolean isPersistent()
      {
          return _persistent;
      }
  
      public String getType()
      {
          return _type;
      }
  
      public void setInitialValue(String initialValue)
      {
          _initialValue = initialValue;
      }
  
  	/**
  	 *  Sets the name of the property.  This should not be changed
  	 *  once this PropertySpecification is added to
  	 *  a {@link net.sf.tapestry.spec.ComponentSpecification}.
  	 * 
  	 **/
  	
      public void setName(String name)
      {
          _name = name;
      }
  
      public void setPersistent(boolean persistant)
      {
          _persistent = persistant;
      }
  
      public void setType(String type)
      {
          _type = type;
      }
  
  }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/c9/Four.java
  
  Index: Four.java
  ===================================================================
  package net.sf.tapestry.junit.mock.c9;
  
  import net.sf.tapestry.html.BasePage;
  
  /**
   *  Used to validate that the enhancer will reject classes where the
   *  property exists (that is, with non-abstract accessors).
   *
   *  @author Howard Lewis Ship
   *  @version $Id: Four.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   **/
  
  public class Four extends BasePage
  {
  	private String _word;
  	
      public String getWord()
      {
          return _word;
      }
  
      public void setWord(String word)
      {
          _word = word;
      }
  
  }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/c9/Five.java
  
  Index: Five.java
  ===================================================================
  package net.sf.tapestry.junit.mock.c9;
  
  import net.sf.tapestry.html.BasePage;
  
  /**
   *  More testing for non-abstract accessor methods.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: Five.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   **/
  
  public class Five extends BasePage
  {
  	public void setWord(String value)
  	{
  		// Nothing, but it screws up the works.
  	}
  }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/c9/Seven.java
  
  Index: Seven.java
  ===================================================================
  package net.sf.tapestry.junit.mock.c9;
  
  import net.sf.tapestry.IRequestCycle;
  import net.sf.tapestry.html.BasePage;
  
  /**
   *  One giant test page to test all kinds of persistent properties.  Eight
   *  scalar types and an object type.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: Seven.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   **/
  
  public abstract class Seven extends BasePage
  {
      abstract public boolean getBooleanValue();
      abstract public byte getByteValue();
      abstract public char getCharValue();
      abstract public double getDoubleValue();
      abstract public float getFloatValue();
      abstract public int getIntValue();
      abstract public long getLongValue();
      abstract public short getShortValue();
      abstract public String getStringValue();
      abstract public void setBooleanValue(boolean booleanValue);
      abstract public void setByteValue(byte byteValue);
      abstract public void setCharValue(char charValue);
      abstract public void setDoubleValue(double doubleValue);
      abstract public void setFloatValue(float floatValue);
      abstract public void setIntValue(int intValue);
      abstract public void setLongValue(long longValue);
      abstract public void setShortValue(short shortValue);
      abstract public void setStringValue(String stringValue);
  
      public void finishLoad()
      {
          setBooleanValue(true);
          setByteValue((byte) 'A');
          setShortValue((short) 97);
          setCharValue('Z');
          setDoubleValue(3.2);
          setFloatValue(-22.7f);
          setIntValue(100);
          setLongValue(32000000);
          setStringValue("Magic");
      }
  
      public void update(IRequestCycle cycle)
      {
          setBooleanValue(false);
          setByteValue((byte) 'Q');
          setShortValue((short) 21);
          setCharValue('f');
          setDoubleValue(9.87);
          setFloatValue(-202.2f);
          setIntValue(3097);
          setLongValue(132000001);
          setStringValue("Marker");
      }
  
  }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/c9/Three.java
  
  Index: Three.java
  ===================================================================
  package net.sf.tapestry.junit.mock.c9;
  
  import net.sf.tapestry.html.BasePage;
  
  /**
   *  Demonstration for a class that has abstract accessor methods and initializes
   *  the property in finishLoad().
   *
   *  @author Howard Lewis Ship
   *  @version $Id: Three.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   **/
  
  public abstract class Three extends BasePage
  {
      public abstract String getWord();
  
      public abstract void setWord(String word);
  
      protected void finishLoad()
      {
          setWord("Tapestry");
      }
  
  }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/mock/c9/Six.java
  
  Index: Six.java
  ===================================================================
  package net.sf.tapestry.junit.mock.c9;
  
  import net.sf.tapestry.html.BasePage;
  
  /**
   *  This is used in a test where the types do not match up.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: Six.java,v 1.1 2003/01/24 00:49:35 hlship Exp $
   *  @since 2.4
   **/
  
  public abstract class Six extends BasePage
  {
  	abstract public int getValue();
  	
  	abstract public void setValue(int value);
  }
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/io/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/io/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 May 2002 21:37:15 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:35 -0000	1.5
  @@ -16,7 +16,7 @@
   basic scalar types, Strings and serializable objects into a String format.  The eventual
   purpose is to safely encode information into URLs or as HTTP Cookies.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.4       +30 -3     jakarta-tapestry/framework/src/net/sf/tapestry/parse/Tapestry_1_4.dtd
  
  Index: Tapestry_1_4.dtd
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/parse/Tapestry_1_4.dtd,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Tapestry_1_4.dtd	22 Jan 2003 16:47:27 -0000	1.3
  +++ Tapestry_1_4.dtd	24 Jan 2003 00:49:35 -0000	1.4
  @@ -27,12 +27,13 @@
   - added value attribute to <property>
   - renamed <component-alias> to <component-type>
   - added <listener-binding> element
  +- added <property-specification> element
   -->
   
   <!-- =======================================================
   Entity: attribute-flag
   
  -For entity attributesthat take a boolean value, defines 'yes' and 'no'.
  +For entity attributes that take a boolean value, defines 'yes' and 'no'.
   The default varies, so isn't included here.
   -->
   <!ENTITY % attribute-flag "(yes|no)">
  @@ -202,7 +203,7 @@
   -->
   <!ELEMENT component-specification 
   	(description*, parameter*, reserved-parameter*, property*,
  -	(bean |	component | external-asset | context-asset | private-asset)*)>
  +	(bean |	component | external-asset | context-asset | private-asset | property-specification)*)>
   <!ATTLIST component-specification
     class CDATA #IMPLIED
     allow-body %attribute-flag; "yes"
  @@ -377,7 +378,7 @@
     class: The Java class to instantiate for the component.
   -->
   <!ELEMENT page-specification (description*, property*,
  -    (bean | component | external-asset | context-asset | private-asset)*)>
  +    (bean | component | external-asset | context-asset | private-asset | property-specification)*)>
   <!ATTLIST page-specification
     class CDATA #IMPLIED
   >
  @@ -443,6 +444,32 @@
   <!ATTLIST property
     name CDATA #REQUIRED
     value CDATA #IMPLIED
  +>
  +
  +<!-- =======================================================
  +Element: property-specification
  +Appears in: component-specification, component-specification
  +
  +Identifies a transient or persistent property.
  +
  +Attributes:
  +  name: The name of the property.
  +  type: The type of the value, either the name of a scalar type,
  +    or the fully qualified name of a class.  If omitted,
  +    java.lang.Object is used.
  +  persistant: If "yes", the value will be made persistant.  Default
  +    is "no".
  +  initial-value:  If provided, this is an OGNL expression used
  +    to initialize the property.
  +    
  +-->
  +
  +<!ELEMENT property-specification EMPTY>
  +<!ATTLIST property-specification
  +  name CDATA #REQUIRED
  +  type CDATA #IMPLIED
  +  persistent %attribute-flag; "no"
  +  initial-value CDATA #IMPLIED
   >
   
   <!-- =======================================================
  
  
  
  1.37      +39 -5     jakarta-tapestry/framework/src/net/sf/tapestry/parse/SpecificationParser.java
  
  Index: SpecificationParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/parse/SpecificationParser.java,v
  retrieving revision 1.36
  retrieving revision 1.37
  diff -u -r1.36 -r1.37
  --- SpecificationParser.java	22 Jan 2003 16:47:27 -0000	1.36
  +++ SpecificationParser.java	24 Jan 2003 00:49:35 -0000	1.37
  @@ -78,6 +78,7 @@
   import net.sf.tapestry.spec.ILibrarySpecification;
   import net.sf.tapestry.spec.ListenerBindingSpecification;
   import net.sf.tapestry.spec.ParameterSpecification;
  +import net.sf.tapestry.spec.PropertySpecification;
   import net.sf.tapestry.spec.SpecFactory;
   import net.sf.tapestry.util.IPropertyHolder;
   import net.sf.tapestry.util.xml.AbstractDocumentParser;
  @@ -773,6 +774,12 @@
                   specification.setDescription(getValue(node));
                   continue;
               }
  +
  +            if (isElement(node, "property-specification"))
  +            {
  +                convertPropertySpecification(specification, node);
  +                continue;
  +            }
           }
   
           return specification;
  @@ -1045,13 +1052,13 @@
       {
           String name = getAttribute(node, "name");
           String value = getAttribute(node, attributeName);
  -        
  +
           // In several cases, the 1.4 DTD makes the attribute optional and
           // allows the value to be to the body of the element.
  -        
  +
           if (value == null)
  -        	value = getValue(node);
  -        	
  +            value = getValue(node);
  +
           BindingSpecification binding = _factory.createBindingSpecification(type, value);
   
           component.setBinding(name, binding);
  @@ -1249,6 +1256,33 @@
           Object objectValue = converter.convert(value);
   
           spec.addConfiguration(propertyName, objectValue);
  +    }
  +
  +    /** @since 2.4 **/
  +
  +    private void convertPropertySpecification(ComponentSpecification spec, Node node)
  +        throws DocumentParseException
  +    {
  +        PropertySpecification ps = _factory.createPropertySpecification();
  +
  +        String name = getAttribute(node, "name");
  +
  +        validate(name, PROPERTY_NAME_PATTERN, "SpecificationParser.invalid-property-name");
  +
  +        ps.setName(name);
  +
  +        String type = getAttribute(node, "type");
  +
  +        if (!Tapestry.isNull(type))
  +            ps.setType(type);
  +
  +        boolean persistent = getBooleanAttribute(node, "persistent");
  +
  +        ps.setPersistent(persistent);
  +
  +        ps.setInitialValue(getAttribute(node, "initial-value"));
  +
  +        spec.addPropertySpecification(ps);
       }
   
   }
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/parse/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/parse/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:50:42 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:35 -0000	1.4
  @@ -8,7 +8,7 @@
   
   <p>Classes used when parsing templates, application and component specifications.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/script/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/script/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 May 2002 21:37:14 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:35 -0000	1.5
  @@ -13,7 +13,7 @@
   as {@link net.sf.tapestry.html.Script} (used for
   including arbitrary user-written JavaScript).
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/lib/ext/bcel-5.0.jar
  
  	<<Binary file>>
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/html/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/html/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:46:09 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:36 -0000	1.4
  @@ -9,7 +9,7 @@
   <p>Components specific to the creation of HTML pages, including sophisticated
   DHTML JavaScript effects.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.9       +12 -11    jakarta-tapestry/framework/src/net/sf/tapestry/html/Frame.java
  
  Index: Frame.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/html/Frame.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Frame.java	13 Jan 2003 03:33:24 -0000	1.8
  +++ Frame.java	24 Jan 2003 00:49:36 -0000	1.9
  @@ -61,6 +61,7 @@
   import net.sf.tapestry.IMarkupWriter;
   import net.sf.tapestry.IRequestCycle;
   import net.sf.tapestry.RequestCycleException;
  +import net.sf.tapestry.Tapestry;
   
   /**
    *  Implements a &lt;frame&gt; within a &lt;frameset&gt;.
  @@ -74,26 +75,26 @@
   
   public class Frame extends AbstractComponent
   {
  -	private String _targetPage;
  -	    
  -    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) throws RequestCycleException
  +    private String _targetPage;
  +
  +    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
  +        throws RequestCycleException
       {
           if (cycle.isRewinding())
               return;
  -            
  +
           IEngine engine = cycle.getEngine();
  -        IEngineService pageService = engine.getService(IEngineService.PAGE_SERVICE);
  -        
  +        IEngineService pageService = engine.getService(Tapestry.PAGE_SERVICE);
  +
           Gesture g = pageService.buildGesture(cycle, this, new String[] { _targetPage });
  -        
  +
           writer.beginEmpty("frame");
           writer.attribute("src", g.getURL());
  -        
  +
           generateAttributes(writer, cycle);
  -            
  +
           writer.closeTag();
       }
  -
   
       public String getTargetPage()
       {
  
  
  
  1.17      +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/html/Shell.java
  
  Index: Shell.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/html/Shell.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- Shell.java	17 Jan 2003 17:40:25 -0000	1.16
  +++ Shell.java	24 Jan 2003 00:49:36 -0000	1.17
  @@ -176,7 +176,7 @@
           // Here comes the tricky part ... have to assemble a complete URL
           // for the current page.
   
  -        IEngineService pageService = cycle.getEngine().getService(IEngineService.PAGE_SERVICE);
  +        IEngineService pageService = cycle.getEngine().getService(Tapestry.PAGE_SERVICE);
           String pageName = getPage().getPageName();
   
           Gesture g = pageService.buildGesture(cycle, null, new String[] { pageName });
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/exception/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/exception/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	3 May 2002 18:12:57 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:36 -0000	1.2
  @@ -11,7 +11,7 @@
   the type, message and other properties of an exception, and understands about nested
   exceptions.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.3       +2 -2      jakarta-tapestry/examples/Vlib/context/WEB-INF/Border.html
  
  Index: Border.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/WEB-INF/Border.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Border.html	17 Jan 2003 17:45:20 -0000	1.2
  +++ Border.html	24 Jan 2003 00:49:36 -0000	1.3
  @@ -124,7 +124,7 @@
   
   	<tr bgcolor="#000000">
   		<td colspan="2" class="clsFooter" align="center" valign="bottom">&#169;2000-2002
  -		<a class="clsFooterLink" href="mailto:hship@users.sf.net">Howard Lewis Ship</a>.
  +		<a class="clsFooterLink" href="mailto:hlship@apache.org">Howard Lewis Ship</a>.
   		All rights reserved.
   
           <span jwcid="@contrib:InspectorButton" disabled="[[ ! page.engine.debugEnabled ]]"/>
  
  
  
  1.11      +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/asset/PrivateAsset.java
  
  Index: PrivateAsset.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/asset/PrivateAsset.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- PrivateAsset.java	17 Jan 2003 17:40:26 -0000	1.10
  +++ PrivateAsset.java	24 Jan 2003 00:49:36 -0000	1.11
  @@ -127,7 +127,7 @@
   
           String[] parameters = new String[] { localizedResourcePath };
   
  -        IEngineService service = cycle.getEngine().getService(IEngineService.ASSET_SERVICE);
  +        IEngineService service = cycle.getEngine().getService(Tapestry.ASSET_SERVICE);
   
           Gesture g = service.buildGesture(cycle, null, parameters);
   
  
  
  
  1.3       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/asset/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/asset/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	5 Sep 2002 00:39:49 -0000	1.2
  +++ package.html	24 Jan 2003 00:49:36 -0000	1.3
  @@ -9,7 +9,7 @@
   <p>Implementations of {@link net.sf.tapestry.IAsset}, as well as
   the {@link net.sf.tapestry.asset.AssetExternalizer}, used to handle private assets.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.10      +14 -9     jakarta-tapestry/framework/src/net/sf/tapestry/asset/AssetService.java
  
  Index: AssetService.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/asset/AssetService.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- AssetService.java	13 Jan 2003 03:33:15 -0000	1.9
  +++ AssetService.java	24 Jan 2003 00:49:36 -0000	1.10
  @@ -129,16 +129,17 @@
       public Gesture buildGesture(IRequestCycle cycle, IComponent component, Object[] parameters)
       {
           if (Tapestry.size(parameters) != 1)
  -            throw new ApplicationRuntimeException(Tapestry.getString("service-single-parameter", ASSET_SERVICE));
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString("service-single-parameter", Tapestry.ASSET_SERVICE));
   
           // Service is stateless
   
  -        return assembleGesture(cycle, ASSET_SERVICE, null, parameters, false);
  +        return assembleGesture(cycle, Tapestry.ASSET_SERVICE, null, parameters, false);
       }
   
       public String getName()
       {
  -        return ASSET_SERVICE;
  +        return Tapestry.ASSET_SERVICE;
       }
   
       private static String getMimeType(String path)
  @@ -167,17 +168,21 @@
        *
        **/
   
  -    public boolean service(IEngineServiceView engine, IRequestCycle cycle, ResponseOutputStream output)
  +    public boolean service(
  +        IEngineServiceView engine,
  +        IRequestCycle cycle,
  +        ResponseOutputStream output)
           throws ServletException, IOException, RequestCycleException
       {
           Object[] parameters = getParameters(cycle);
   
  -        String resourcePath =  (String)parameters[0];
  -        
  +        String resourcePath = (String) parameters[0];
  +
           URL resourceURL = cycle.getEngine().getResourceResolver().getResource(resourcePath);
   
           if (resourceURL == null)
  -            throw new ApplicationRuntimeException(Tapestry.getString("missing-resource", resourcePath));
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString("missing-resource", resourcePath));
   
           URLConnection resourceConnection = resourceURL.openConnection();
   
  @@ -191,7 +196,7 @@
       }
   
       /**  @since 2.2 **/
  -    
  +
       private void writeAssetContent(
           IEngineServiceView engine,
           IRequestCycle cycle,
  
  
  
  1.3       +2 -2      jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/jdbc/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/jdbc/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	26 Nov 2002 16:35:51 -0000	1.2
  +++ package.html	24 Jan 2003 00:49:36 -0000	1.3
  @@ -14,7 +14,7 @@
   {@link net.sf.tapestry.util.jdbc.StatementAssembly} you don't know in advance which
   you'll get, which is very handy when generating truly dynamic SQL.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/enhance/TestClassFabricator.java
  
  Index: TestClassFabricator.java
  ===================================================================
  package net.sf.tapestry.junit.enhance;
  
  import net.sf.tapestry.ApplicationRuntimeException;
  import net.sf.tapestry.DefaultResourceResolver;
  import net.sf.tapestry.IResourceResolver;
  import net.sf.tapestry.enhance.ClassFabricator;
  import net.sf.tapestry.enhance.EnhanceClassLoader;
  import net.sf.tapestry.enhance.MethodFabricator;
  import net.sf.tapestry.event.PageDetachListener;
  import net.sf.tapestry.event.PageEvent;
  import net.sf.tapestry.html.BasePage;
  import net.sf.tapestry.junit.TapestryTestCase;
  import net.sf.tapestry.util.prop.OgnlUtils;
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.JavaClass;
  import org.apache.bcel.generic.InstructionConstants;
  import org.apache.bcel.generic.InstructionFactory;
  import org.apache.bcel.generic.InstructionList;
  import org.apache.bcel.generic.ObjectType;
  import org.apache.bcel.generic.Type;
  
  /**
   *  Tests the classes used by the 
   *  {@link net.sf.tapestry.enhance.DefaultComponentClassEnhancer} to
   *  construct new classes.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: TestClassFabricator.java,v 1.1 2003/01/24 00:49:37 hlship Exp $
   *  @since 2.4
   **/
  
  public class TestClassFabricator extends TapestryTestCase
  {
  
      public TestClassFabricator(String name)
      {
          super(name);
      }
  
      /**
       *  Test the ability to create a class that implements a read/write property.
       * 
       **/
  
      public void testCreateProperty() throws Exception
      {
          String className = "net.sf.tapestry.junit.enhance.PropertyHolder";
          String fieldName = "_name";
  
          ClassFabricator cf = new ClassFabricator(className, "java.lang.Object");
  
          InstructionFactory f = cf.getInstructionFactory();
  
          cf.addDefaultConstructor();
          cf.addField(Type.STRING, fieldName);
  
          MethodFabricator mf = cf.createMethod(Constants.ACC_PUBLIC, Type.VOID, "setName");
          int nameArgIndex = mf.addArgument(Type.STRING, "name");
  
          InstructionList il = mf.getInstructionList();
  
          il.append(f.createThis());
          il.append(f.createLoad(Type.STRING, nameArgIndex));
          il.append(f.createPutField(className, fieldName, Type.STRING));
          il.append(InstructionConstants.RETURN);
  
          mf.commit();
  
          mf = cf.createMethod(Constants.ACC_PUBLIC, Type.STRING, "getName");
          il = mf.getInstructionList();
  
          il.append(f.createThis());
          il.append(f.createGetField(className, fieldName, Type.STRING));
          il.append(f.createReturn(Type.STRING));
  
          mf.commit();
  
          JavaClass jc = cf.commit();
  
          IResourceResolver resolver = new DefaultResourceResolver();
  
          EnhanceClassLoader cl = new EnhanceClassLoader(resolver.getClassLoader());
  
          Class holderClass = cl.defineClass(jc);
  
          Object holder = holderClass.newInstance();
  
          String value = "abraxis";
  
          OgnlUtils.set("name", resolver, holder, value);
  
          Object actual = OgnlUtils.get("name", resolver, holder);
  
          assertEquals("Holder name property.", value, actual);
      }
  
      /**
       *  Test ability to create a subclass of an existing class
       *  and implement an interface.
       * 
       **/
  
      public void testAddInterface() throws Exception
      {
          ClassFabricator cf =
              new ClassFabricator("net.sf.tapestry.junit.enhance.Foobar", BasePage.class.getName());
  
          cf.addDefaultConstructor();
          cf.addInterface(PageDetachListener.class);
  
          MethodFabricator mf = cf.createMethod("pageDetached");
  
          mf.addArgument(new ObjectType(PageEvent.class.getName()), "event");
  
          InstructionList il = mf.getInstructionList();
  
          il.append(InstructionConstants.RETURN);
  
          mf.commit();
  
          JavaClass jc = cf.commit();
  
          IResourceResolver resolver = new DefaultResourceResolver();
  
          EnhanceClassLoader cl = new EnhanceClassLoader(resolver.getClassLoader());
  
          Class holderClass = cl.defineClass(jc);
  
          Object instance = holderClass.newInstance();
  
          assertEquals("Implements interface", true, instance instanceof PageDetachListener);
      }
  
      public void testFailureAddArgumentsAfterLocals()
      {
          ClassFabricator cf = new ClassFabricator("Foo", "java.lang.Object");
  
          MethodFabricator mf = cf.createMethod("bar");
  
          mf.addArgument(Type.STRING, "param1");
          mf.addLocalVariable(Type.BOOLEAN, "local1");
  
          try
          {
              mf.addArgument(Type.LONG, "param2");
              unreachable();
          }
          catch (IllegalStateException ex)
          {
              checkException(
                  ex,
                  "No more arguments may be added once any local variables are added.");
          }
      }
  
      public void testCreateFailure()
      {
          ClassFabricator cf =
              new ClassFabricator("net.sf.tapestry.junit.enhance.Invalid", "java.lang.Boolean");
  
          JavaClass jc = cf.commit();
  
          IResourceResolver resolver = new DefaultResourceResolver();
  
          EnhanceClassLoader cl = new EnhanceClassLoader(resolver.getClassLoader());
  
          try
          {
              cl.defineClass(jc);
  
              unreachable();
          }
          catch (ApplicationRuntimeException ex)
          {
              checkException(ex, "Cannot inherit from final class");
          }
  
      }
  }
  
  
  1.6       +30 -17    jakarta-tapestry/framework/src/net/sf/tapestry/util/prop/OgnlUtils.java
  
  Index: OgnlUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/prop/OgnlUtils.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- OgnlUtils.java	13 Jan 2003 03:33:12 -0000	1.5
  +++ OgnlUtils.java	24 Jan 2003 00:49:37 -0000	1.6
  @@ -58,6 +58,7 @@
   import java.util.Map;
   
   import net.sf.tapestry.ApplicationRuntimeException;
  +import net.sf.tapestry.Tapestry;
   
   import ognl.ClassResolver;
   import ognl.Ognl;
  @@ -86,7 +87,7 @@
        *  @throws ApplicationRuntimeException if the expression can not be parsed.
        * 
        **/
  -    
  +
       public static synchronized Object getParsedExpression(String expression)
       {
           Object result = _cache.get(expression);
  @@ -99,7 +100,9 @@
               }
               catch (OgnlException ex)
               {
  -                throw new ApplicationRuntimeException(ex);
  +                throw new ApplicationRuntimeException(
  +                    Tapestry.getString("OgnlUtils.unable-to-parse-expression", expression),
  +                    ex);
               }
   
               _cache.put(expression, result);
  @@ -107,7 +110,7 @@
   
           return result;
       }
  -    
  +
       /**
        *  Parses and caches the expression and uses it to update
        *  the target object with the provided value.
  @@ -116,12 +119,12 @@
        *  can not be parsed, or the target can not be updated.
        * 
        **/
  -    
  +
       public static void set(String expression, ClassResolver resolver, Object target, Object value)
       {
           set(getParsedExpression(expression), resolver, target, value);
       }
  -  
  +
       /** 
        *  Updates the target object with the provided value.
        * 
  @@ -129,22 +132,27 @@
        *  @throws ApplicationRuntimeException if the target can not be updated.
        * 
        **/
  - 
  -     
  +
       public static void set(Object expression, ClassResolver resolver, Object target, Object value)
       {
           try
           {
               Map context = Ognl.createDefaultContext(target, resolver);
  -            
  +
               Ognl.setValue(expression, context, target, value);
           }
           catch (OgnlException ex)
           {
  -            throw new ApplicationRuntimeException(ex);
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString(
  +                    "OgnlUtils.unable-to-update-expression",
  +                    "<parsed expression>",
  +                    target,
  +                    value),
  +                ex);
           }
       }
  -    
  +
       /**
        *   Returns the value of the expression evaluated against
        *   the object.
  @@ -156,21 +164,26 @@
        *   if the value can not be obtained from the object.
        * 
        **/
  -    
  +
       public static Object get(Object expression, ClassResolver resolver, Object object)
       {
           try
           {
               Map context = Ognl.createDefaultContext(object, resolver);
  -            
  +
               return Ognl.getValue(expression, context, object);
           }
           catch (OgnlException ex)
           {
  -            throw new ApplicationRuntimeException(ex);
  +            throw new ApplicationRuntimeException(
  +                Tapestry.getString(
  +                    "OgnlUtils.unable-to-read-expression",
  +                    "<parsed expression>",
  +                    object),
  +                ex);
           }
       }
  -    
  +
       /**
        *   Returns the value of the expression evaluated against
        *   the object.
  @@ -180,10 +193,10 @@
        *   expression can not be parsed, or the value
        *   not obtained from the object.
        **/
  -    
  +
       public static Object get(String expression, ClassResolver resolver, Object object)
       {
           return get(getParsedExpression(expression), resolver, object);
       }
  -     
  +
   }
  
  
  
  1.6       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/prop/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/prop/package.html,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- package.html	28 Aug 2002 21:20:53 -0000	1.5
  +++ package.html	24 Jan 2003 00:49:37 -0000	1.6
  @@ -13,7 +13,7 @@
   Tapestry switch to use the <a href="http://www.ognl.org">Object Graph
   Navigation Library</a> which is much more powerful.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/record/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/record/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 May 2002 21:37:14 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:37 -0000	1.5
  @@ -9,7 +9,7 @@
   <p>Abstract and simple (memory-based) implementations of
   {@link net.sf.tapestry.IPageRecorder}.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.1                  jakarta-tapestry/junit/context8/README
  
  Index: README
  ===================================================================
  This context contains tests use to check that the default template extension may be overriden.
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/enhance/EnhanceClassLoader.java
  
  Index: EnhanceClassLoader.java
  ===================================================================
  package net.sf.tapestry.enhance;
  
  import net.sf.tapestry.ApplicationRuntimeException;
  import net.sf.tapestry.Tapestry;
  
  import org.apache.bcel.classfile.JavaClass;
  
  /**
   *  A class loader that can be used to create new classes 
   *  as needed.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: EnhanceClassLoader.java,v 1.1 2003/01/24 00:49:37 hlship Exp $
   *  @since 2.4
   * 
   **/
  
  public class EnhanceClassLoader extends ClassLoader
  {
  
      public EnhanceClassLoader(ClassLoader parentClassLoader)
      {
          super(parentClassLoader);
      }
  
      /**
       *  Defines the new class.
       * 
       *  @throws ApplicationRuntimeException if defining the class fails.
       * 
       **/
  
      public Class defineClass(JavaClass enhancedClass)
      {
          byte[] byteCode = enhancedClass.getBytes();
  
          try
          {
              return defineClass(enhancedClass.getClassName(), byteCode, 0, byteCode.length);
          }
          catch (Throwable ex)
          {
              throw new ApplicationRuntimeException(
                  Tapestry.getString(
                      "EnhancedClassLoader.unable-to-define-class",
                      enhancedClass,
                      ex.getMessage()),
                  ex);
          }
      }
  }
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/enhance/package.html
  
  Index: package.html
  ===================================================================
  Classes used for performing dynamic bytecode enhancement of component and page classes.
  
  @author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/enhance/ClassFabricator.java
  
  Index: ClassFabricator.java
  ===================================================================
  package net.sf.tapestry.enhance;
  
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.Field;
  import org.apache.bcel.classfile.JavaClass;
  import org.apache.bcel.generic.*;
  
  /**
   *  Class used to simplify the generation of new classes as
   *  a wrapper around BCEL.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: ClassFabricator.java,v 1.1 2003/01/24 00:49:37 hlship Exp $
   *  @since 2.4
   **/
  
  public class ClassFabricator
  {
      private ClassGen _classGen;
      private InstructionFactory _instructionFactory;
  
      /**
       *  Creates a public final class.
       * 
       **/
  
      public ClassFabricator(String className, String parentClassName)
      {
          this(className, parentClassName, Constants.ACC_FINAL | Constants.ACC_PUBLIC);
      }
  
      /**
       *  General constructor, creates a new instance using the supplied
       *  parameters.  ACC_SUPER is automatically added to the access flags.
       * 
       **/
  
      public ClassFabricator(String className, String parentClassName, int accessFlags)
      {
          _classGen =
              new ClassGen(
                  className,
                  parentClassName,
                  "<synthetic>",
                  accessFlags | Constants.ACC_SUPER,
                  null);
      }
  
  	/**
  	 *  Creates a new {@link MethodFabricator}.  Invoke
  	 *  {@link MethodFabricator#getInstructionList()}
  	 *  to obtain the (initially empty) instruction list
  	 *  for the method.
  	 * 
  	 **/
  	
      public MethodFabricator createMethod(int accessFlags, Type returnType, String methodName)
      {
          return new MethodFabricator(_classGen, accessFlags, returnType, methodName);
      }
  
      /**
       *  Creates a default public method that returns void.
       * 
       **/
  
      public MethodFabricator createMethod(String methodName)
      {
          return createMethod(Constants.ACC_PUBLIC, Type.VOID, methodName);
      }
  
      /**
       *  Adds a private instance variable of the given type and name.
       * 
       **/
  
      public void addField(Type type, String name)
      {
          addField(Constants.ACC_PRIVATE, type, name);
      }
  
      /**
       *  Adds a field with the given access type, type and name.
       * 
       **/
  
      public void addField(int accessFlags, Type type, String name)
      {
          FieldGen fg = new FieldGen(accessFlags, type, name, _classGen.getConstantPool());
  
          Field f = fg.getField();
  
          _classGen.addField(f);
      }
  
      /**
       *  Adds a public, no-arguments constructor.
       * 
       **/
  
      public void addDefaultConstructor()
      {
          _classGen.addEmptyConstructor(Constants.ACC_PUBLIC);
      }
  
  
  	/**
  	 *  Adds an interface to the list of interfaces implemented
  	 *  by the class.
  	 * 
  	 **/
  	
  	public void addInterface(String interfaceName)
  	{
  		_classGen.addInterface(interfaceName);
  	}
  	
  	public void addInterface(Class interfaceClass)
  	{
  		addInterface(interfaceClass.getName());
  	}
  	
  	public InstructionFactory getInstructionFactory()
  	{
  		if (_instructionFactory == null)
  			_instructionFactory = new InstructionFactory(_classGen);
  		
  		return _instructionFactory;
  	}
  
      /**
       *  Invoked very much last, to create the
       *  new {@link org.apache.bcel.classfile.JavaClass} instance.
       * 
       **/
  
      public JavaClass commit()
      {
          return _classGen.getJavaClass();
      }
      
      /**
       *  Returns the fully qualified class name.
       * 
       **/
      
      public String getClassName()
      {
      	return _classGen.getClassName();
      }
      
      /**
       *  Returns the mutable constant pool.
       * 
       **/
      
      public ConstantPoolGen getConstantPool()
      {
      	return _classGen.getConstantPool();
      }
  }
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/enhance/MethodFabricator.java
  
  Index: MethodFabricator.java
  ===================================================================
  package net.sf.tapestry.enhance;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import net.sf.tapestry.Tapestry;
  
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.Method;
  import org.apache.bcel.generic.ClassGen;
  import org.apache.bcel.generic.InstructionHandle;
  import org.apache.bcel.generic.InstructionList;
  import org.apache.bcel.generic.LocalVariableGen;
  import org.apache.bcel.generic.MethodGen;
  import org.apache.bcel.generic.Type;
  
  /**
   *  Wrapper around {@link org.apache.bcel.generic.MethodGen} used to
   *  simplify the creation of new methods within a new class.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: MethodFabricator.java,v 1.1 2003/01/24 00:49:37 hlship Exp $
   *  @since 2.4
   **/
  
  public class MethodFabricator
  {
      private ClassGen _classGen;
      private MethodGen _methodGen;
      private InstructionList _instructionList = new InstructionList();
      private List _arguments = new ArrayList();
      private boolean _argumentsCommitted = false;
  
      private static class Argument
      {
          Type _type;
          String _name;
  
          Argument(Type type, String name)
          {
              _type = type;
              _name = name;
          }
      }
  
      MethodFabricator(ClassGen classGen, int accessFlags, Type returnType, String methodName)
      {
          _classGen = classGen;
          _methodGen =
              new MethodGen(
                  accessFlags,
                  returnType,
                  null,
                  null,
                  methodName,
                  _classGen.getClassName(),
                  _instructionList,
                  _classGen.getConstantPool());
      }
  
      /**
       *  Adds an argument to the method.  Arguments must be
       *  added in order.  Returns the index of the added
       *  argument.  This is an implicit argument in slot 0,
       *  the first explicit argument is in slot 1.
       * 
       *  <p>All arguments must be added before any local variables
       *  are added.
       * 
       *  @throws IllegalStateException if arguments may not be added.
       **/
  
      public int addArgument(Type type, String name)
      {
          if (_argumentsCommitted)
              throw new IllegalStateException(
                  Tapestry.getString("MethodFabricator.no-more-arguments"));
  
          _arguments.add(new Argument(type, name));
  
          return _arguments.size();
      }
  
      /**
       *  Adds a local variable of the given type, returning its index.
       *  Local variables come after any arguments.  Arguments may not
       *  be added after local variables.
       * 
       **/
  
      public int addLocalVariable(Type type, String name)
      {
          if (!_argumentsCommitted)
              commitArguments();
  
          LocalVariableGen l = _methodGen.addLocalVariable(name, type, null, null);
  
          return l.getIndex();
      }
  
      /**
       *  Returns the instruction list for the method
       *  being created.
       * 
       **/
  
      public InstructionList getInstructionList()
      {
          return _instructionList;
      }
  
      /**
       *  Commits the method; this is invoked last.  It updates
       *  the {@link org.apache.bcel.generic.MethodGen} with
       *  any arguments that have been added, then
       *  creates the {@link org.apache.bcel.classfile.Method}
       *  object and adds it to the {@link ClassGen}.
       * 
       **/
  
      public void commit()
      {
          if (!_argumentsCommitted)
              commitArguments();
  
          InstructionHandle start = _instructionList.getStart();
          InstructionHandle end = _instructionList.getEnd();
  
          LocalVariableGen[] variables = _methodGen.getLocalVariables();
          for (int i = 0; i < variables.length; i++)
          {
              variables[i].setStart(start);
              variables[i].setEnd(end);
          }
  
          _methodGen.setMaxStack();
  
          Method m = _methodGen.getMethod();
  
          _classGen.addMethod(m);
      }
  
      /**
       *  Invoked to update the {@link org.apache.bcel.generic.MethodGen} with
       *  any arguments.  This must be done before adding any local variables.
       * 
       **/
  
      private void commitArguments()
      {
          int count = _arguments.size();
          if (count > 0)
          {
              Type[] types = new Type[count];
              String[] names = new String[count];
  
              for (int i = 0; i < count; i++)
              {
                  Argument a = (Argument) _arguments.get(i);
  
                  types[i] = a._type;
                  names[i] = a._name;
  
                  _methodGen.addLocalVariable(a._name, a._type, null, null);
              }
  
              _methodGen.setArgumentNames(names);
              _methodGen.setArgumentTypes(types);
          }
  
          _argumentsCommitted = true;
      }
  }
  
  
  
  1.1                  jakarta-tapestry/framework/src/net/sf/tapestry/enhance/DefaultComponentClassEnhancer.java
  
  Index: DefaultComponentClassEnhancer.java
  ===================================================================
  package net.sf.tapestry.enhance;
  
  import java.beans.BeanInfo;
  import java.beans.IntrospectionException;
  import java.beans.Introspector;
  import java.beans.PropertyDescriptor;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import net.sf.tapestry.ApplicationRuntimeException;
  import net.sf.tapestry.IComponentClassEnhancer;
  import net.sf.tapestry.IResourceResolver;
  import net.sf.tapestry.Tapestry;
  import net.sf.tapestry.spec.ComponentSpecification;
  import net.sf.tapestry.spec.PropertySpecification;
  import org.apache.bcel.Constants;
  import org.apache.bcel.classfile.JavaClass;
  import org.apache.bcel.generic.BasicType;
  import org.apache.bcel.generic.InstructionConstants;
  import org.apache.bcel.generic.InstructionFactory;
  import org.apache.bcel.generic.InstructionList;
  import org.apache.bcel.generic.ObjectType;
  import org.apache.bcel.generic.PUSH;
  import org.apache.bcel.generic.Type;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  /**
   *  Default implementation of {@link net.sf.tapestry.IComponentClassEnhancer}.
   *
   *  @author Howard Lewis Ship
   *  @version $Id: DefaultComponentClassEnhancer.java,v 1.1 2003/01/24 00:49:37 hlship Exp $
   *  @since 2.4
   * 
   **/
  
  public class DefaultComponentClassEnhancer implements IComponentClassEnhancer
  {
      private static final Log LOG = LogFactory.getLog(DefaultComponentClassEnhancer.class);
  
      /**
       *  UID used to generate new class names.
       * 
       **/
  
      private int _uid = 0;
  
      /**
       *  Map of Class, keyed on ComponentSpecification.
       * 
       **/
  
      private Map _cachedClasses = new HashMap();
      private IResourceResolver _resolver;
      private EnhanceClassLoader _classLoader;
  
      /**
       *  Map of type (as Class), keyed on type name. 
       * 
       **/
  
      private Map _typeMap = new HashMap();
  
      /**
       *  Map of type (as Type), keyed on type name.
       * 
       **/
  
      private Map _objectTypeMap = new HashMap();
  
      public DefaultComponentClassEnhancer(IResourceResolver resolver)
      {
          _resolver = resolver;
          _classLoader = new EnhanceClassLoader(resolver.getClassLoader());
  
          initializeTypeMaps();
      }
  
      public synchronized void reset()
      {
          _cachedClasses.clear();
          initializeTypeMaps();
      }
  
      private void initializeTypeMaps()
      {
          _typeMap.clear();
          _objectTypeMap.clear();
  
          recordType("boolean", boolean.class, Type.BOOLEAN);
          recordType("short", short.class, Type.SHORT);
          recordType("int", int.class, Type.INT);
          recordType("long", long.class, Type.LONG);
          recordType("float", float.class, Type.FLOAT);
          recordType("double", double.class, Type.DOUBLE);
          recordType("char", char.class, Type.CHAR);
          recordType("byte", byte.class, Type.BYTE);
      }
  
      private void recordType(String name, Class type, Type objectType)
      {
          _typeMap.put(name, type);
          _objectTypeMap.put(name, objectType);
      }
  
      public synchronized Class getEnhancedClass(
          ComponentSpecification specification,
          String className)
      {
          Class result = (Class) _cachedClasses.get(specification);
  
          if (result == null)
          {
              result = constructComponentClass(specification, className);
  
              _cachedClasses.put(specification, result);
          }
  
          return result;
      }
  
      /**
       *  Returns the class to be used for the component, which is either
       *  the class with the given name, or an enhanced subclass.
       * 
       **/
  
      protected Class constructComponentClass(ComponentSpecification specification, String className)
      {
          Class result = _resolver.findClass(className);
  
          if (needsEnhancement(specification))
              result = createEnhancedSubclass(result, specification);
  
          return result;
      }
  
      /**
       *  Examines the specification, identifies if any enhancements will be needed.
       *  This implementation looks for the presence of any
       *  {@link net.sf.tapestry.spec.PropertySpecification}s.
       * 
       **/
  
      protected boolean needsEnhancement(ComponentSpecification specification)
      {
          return !specification.getPropertySpecificationNames().isEmpty();
      }
  
      private Class createEnhancedSubclass(Class startClass, ComponentSpecification specification)
      {
          if (LOG.isDebugEnabled())
              LOG.debug(
                  "Enhancing class "
                      + startClass.getName()
                      + " for "
                      + specification.getSpecificationLocation());
  
          Class result = null;
  
          String startClassName = startClass.getName();
          String enhancedName = startClassName + "$Enhance_" + _uid++;
  
          ClassFabricator cf = new ClassFabricator(enhancedName, startClassName);
  
          cf.addDefaultConstructor();
  
          List names = specification.getPropertySpecificationNames();
          int count = names.size();
  
          for (int i = 0; i < count; i++)
          {
              String name = (String) names.get(i);
  
              PropertySpecification ps = specification.getPropertySpecification(name);
  
              createProperty(cf, startClass, ps);
          }
  
          JavaClass jc = cf.commit();
  
          result = _classLoader.defineClass(jc);
  
          if (LOG.isDebugEnabled())
              LOG.debug("Finished creating enhanced class " + result.getName());
  
          return result;
      }
  
      /**
       *  Invoked to create the specified property.  Checks that the superclass provides
       *  either abstract accessors or none at all.  Creates the file, creates 
       *  the accessors, creates initialization code.
       * 
       **/
  
      protected void createProperty(ClassFabricator cf, Class startClass, PropertySpecification ps)
      {
          String propertyName = ps.getName();
  
          if (LOG.isDebugEnabled())
              LOG.debug("Establishing property " + propertyName);
  
          String type = ps.getType();
          Class propertyType = convertPropertyType(type);
  
          checkAccessors(startClass, propertyName, propertyType);
  
          String fieldName = "_$" + propertyName;
  
          Type fieldType = getObjectType(type);
  
          cf.addField(fieldType, fieldName);
  
          createAccessor(cf, fieldType, fieldName, propertyName);
          createMutator(cf, fieldType, fieldName, propertyName, ps.isPersistent());
      }
  
      protected void createAccessor(
          ClassFabricator cf,
          Type fieldType,
          String fieldName,
          String propertyName)
      {
          String methodName = buildMethodName("get", propertyName);
  
          MethodFabricator mf = cf.createMethod(Constants.ACC_PUBLIC, fieldType, methodName);
  
          InstructionList il = mf.getInstructionList();
          InstructionFactory factory = cf.getInstructionFactory();
  
          il.append(factory.createThis());
          il.append(factory.createGetField(cf.getClassName(), fieldName, fieldType));
          il.append(factory.createReturn(fieldType));
  
          mf.commit();
      }
  
      protected void createMutator(
          ClassFabricator cf,
          Type fieldType,
          String fieldName,
          String propertyName,
          boolean isPersistent)
      {
          String methodName = buildMethodName("set", propertyName);
  
          MethodFabricator mf = cf.createMethod(methodName);
          mf.addArgument(fieldType, propertyName);
  
          InstructionList il = mf.getInstructionList();
          InstructionFactory factory = cf.getInstructionFactory();
  
          il.append(factory.createThis());
          il.append(factory.createLoad(fieldType, 1));
          il.append(factory.createPutField(cf.getClassName(), fieldName, fieldType));
  
          // Persistent properties must invoke fireObservedChange
  
          if (isPersistent)
          {
              il.append(factory.createThis());
              il.append(new PUSH(cf.getConstantPool(), propertyName));
              il.append(factory.createLoad(fieldType, 1));
  
              Type argumentType = convertToArgumentType(fieldType);
  
              il.append(
                  factory.createInvoke(
                      cf.getClassName(),
                      "fireObservedChange",
                      Type.VOID,
                      new Type[] { Type.STRING, argumentType },
                      Constants.INVOKEVIRTUAL));
          }
  
          il.append(InstructionConstants.RETURN);
  
          mf.commit();
      }
  
      /**
       *  Given an arbitrary type, figures out the correct
       *  argument type (for fireObservedChange()) to use.
       * 
       **/
  
      protected Type convertToArgumentType(Type type)
      {
          if (type instanceof BasicType)
              return type;
  
          return Type.OBJECT;
      }
  
      protected String buildMethodName(String prefix, String propertyName)
      {
          StringBuffer result = new StringBuffer(prefix);
  
          char ch = propertyName.charAt(0);
  
          result.append(Character.toUpperCase(ch));
  
          result.append(propertyName.substring(1));
  
          return result.toString();
      }
  
      protected Class convertPropertyType(String type)
      {
          Class result = (Class) _typeMap.get(type);
  
          if (result == null)
          {
              result = _resolver.findClass(type);
  
              _typeMap.put(type, result);
          }
  
          return result;
      }
  
      protected Type getObjectType(String type)
      {
          Type result = (Type) _objectTypeMap.get(type);
  
          if (result == null)
          {
              result = new ObjectType(type);
              _objectTypeMap.put(type, result);
          }
  
          return result;
      }
  
      protected void checkAccessors(Class startClass, String propertyName, Class propertyType)
      {
          BeanInfo info = null;
  
          try
          {
              info = Introspector.getBeanInfo(startClass);
  
          }
          catch (IntrospectionException ex)
          {
              throw new ApplicationRuntimeException(
                  Tapestry.getString(
                      "DefaultComponentClassEnhancer.unable-to-introspect-class",
                      startClass.getName()),
                  ex);
          }
  
          PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
  
          for (int i = 0; i < descriptors.length; i++)
          {
              PropertyDescriptor d = descriptors[i];
  
              if (!d.getName().equals(propertyName))
                  continue;
  
              if (!d.getPropertyType().equals(propertyType))
                  throw new ApplicationRuntimeException(
                      Tapestry.getString(
                          "DefaultComponentClassEnhancer.property-type-mismatch",
                          new Object[] {
                              startClass.getName(),
                              propertyName,
                              d.getPropertyType().getName(),
                              propertyType.getName()}));
  
              Method m = d.getReadMethod();
  
              if (m != null && !Modifier.isAbstract(m.getModifiers()))
                  throw new ApplicationRuntimeException(
                      Tapestry.getString(
                          "DefaultComponentClassEnhancer.non-abstract-read",
                          m.getDeclaringClass().getName(),
                          propertyName));
  
              m = d.getWriteMethod();
  
              if (m != null && !Modifier.isAbstract(m.getModifiers()))
                  throw new ApplicationRuntimeException(
                      Tapestry.getString(
                          "DefaultComponentClassEnhancer.non-abstract-write",
                          m.getDeclaringClass().getName(),
                          propertyName));
              return;
          }
      }
  }
  
  
  1.13      +54 -1     jakarta-tapestry/junit/src/net/sf/tapestry/junit/parse/SpecificationParserTest.java
  
  Index: SpecificationParserTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/parse/SpecificationParserTest.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- SpecificationParserTest.java	17 Jan 2003 17:41:26 -0000	1.12
  +++ SpecificationParserTest.java	24 Jan 2003 00:49:37 -0000	1.13
  @@ -65,6 +65,7 @@
   import net.sf.tapestry.spec.ILibrarySpecification;
   import net.sf.tapestry.spec.ListenerBindingSpecification;
   import net.sf.tapestry.spec.ParameterSpecification;
  +import net.sf.tapestry.spec.PropertySpecification;
   import net.sf.tapestry.util.xml.DocumentParseException;
   
   /**
  @@ -505,4 +506,56 @@
   
           return buffer.toString();
       }
  +
  +	/** @since 2.4 **/
  +	
  +    public void testPropertySpecifications() throws Exception
  +    {
  +        ComponentSpecification spec = parsePage("PropertySpecifications.page");
  +
  +        checkList(
  +            "propertySpecificationNames",
  +            new String[] { "bool", "init", "persist" },
  +            spec.getPropertySpecificationNames());
  +
  +        PropertySpecification ps = spec.getPropertySpecification("bool");
  +        assertEquals("name", "bool", ps.getName());
  +        assertEquals("persistent", false, ps.isPersistent());
  +        assertEquals("type", "boolean", ps.getType());
  +        assertNull("initialValue", ps.getInitialValue());
  +
  +        ps = spec.getPropertySpecification("init");
  +        assertEquals("name", "init", ps.getName());
  +        assertEquals("persistent", false, ps.isPersistent());
  +        assertEquals("type", "java.lang.Object", ps.getType());
  +        assertEquals("initialValue", "pageName", ps.getInitialValue());
  +
  +        ps = spec.getPropertySpecification("persist");
  +        assertEquals("name", "persist", ps.getName());
  +        assertEquals("persistent", true, ps.isPersistent());
  +        assertEquals("type", "java.lang.Object", ps.getType());
  +        assertNull("initialValue", ps.getInitialValue());
  +
  +        ps = spec.getPropertySpecification("unknown");
  +
  +        assertNull("Unknown PropertySpecification", ps);
  +    }
  +    
  +    /** @since 2.4 **/
  +    
  +    public void testDuplicatePropertySpecification()
  +    throws Exception
  +    {
  +    	try
  +    	{
  +    		parsePage("DuplicatePropertySpecification.page");
  +    		
  +    		unreachable();
  +    	}
  +    	catch (IllegalArgumentException ex)
  +    	{
  +    		checkException(ex, "already contains property specification for property 'bool'");   		
  +    	}
  +    }
  +     
   }
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/parse/DuplicatePropertySpecification.page
  
  Index: DuplicatePropertySpecification.page
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: DuplicatePropertySpecification.page,v 1.1 2003/01/24 00:49:37 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
       	
  <page-specification>
  
  <property-specification name="bool" type="boolean"/>
  <property-specification name="persist" persistent="yes"/>
  <property-specification name="init" initial-value="pageName"/>
  <property-specification name="bool" type="java.lang.Boolean"/>
  
  </page-specification>
  
  
  
  
  1.1                  jakarta-tapestry/junit/src/net/sf/tapestry/junit/parse/PropertySpecifications.page
  
  Index: PropertySpecifications.page
  ===================================================================
  <?xml version="1.0"?>
  <!-- $Id: PropertySpecifications.page,v 1.1 2003/01/24 00:49:37 hlship Exp $ -->
  <!DOCTYPE page-specification PUBLIC 
  	"-//Howard Lewis Ship//Tapestry Specification 1.4//EN" 
  	"http://tapestry.sf.net/dtd/Tapestry_1_4.dtd">
       	
  <page-specification>
  
  <property-specification name="bool" type="boolean"/>
  <property-specification name="persist" persistent="yes"/>
  <property-specification name="init" initial-value="pageName"/>
  
  </page-specification>
  
  
  
  
  1.3       +1 -1      jakarta-tapestry/examples/Tutorial/context/WEB-INF/workbench/Border.html
  
  Index: Border.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Tutorial/context/WEB-INF/workbench/Border.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Border.html	17 Jan 2003 17:45:22 -0000	1.2
  +++ Border.html	24 Jan 2003 00:49:37 -0000	1.3
  @@ -51,7 +51,7 @@
       </form>
       
   <p>
  -&copy; 2000-2003 <a href="mailto:hship@users.sf.net">Howard M. Lewis Ship</a>.
  +&copy; 2000-2003 <a href="mailto:hlship@apache.org">Howard M. Lewis Ship</a>.
   
   <span jwcid="@contrib:InspectorButton" disabled="[[ page.visit.disableInspector ]]"/>
   
  
  
  
  1.6       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/wml/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/wml/package.html,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- package.html	29 May 2002 20:26:12 -0000	1.5
  +++ package.html	24 Jan 2003 00:49:37 -0000	1.6
  @@ -9,7 +9,7 @@
   <p>Very, very basic support for WML.  {@link net.sf.tapestry.wml.Deck} is an alternative to
   {@link net.sf.tapestry.html.BasePage} that provides a <code>text/wml</code> response.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.17      +3 -2      jakarta-tapestry/examples/wap/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/wap/build.xml,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- build.xml	17 Jan 2003 17:41:09 -0000	1.16
  +++ build.xml	24 Jan 2003 00:49:37 -0000	1.17
  @@ -18,7 +18,8 @@
       <pathelement location="${lib.ext.dir}/org.apache.crimson.jar"/>
       <pathelement location="${lib.ext.dir}/${jakarta-oro.jar}"/>
       <pathelement location="${lib.ext.dir}/${ognl.jar}"/>
  -    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>    
  +    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>  
       <pathelement location="${framework.jar}"/>   
     </path>
     
  
  
  
  1.3       +2 -2      jakarta-tapestry/examples/Vlib/context/ApplicationUnavailable.html
  
  Index: ApplicationUnavailable.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/ApplicationUnavailable.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ApplicationUnavailable.html	17 Jan 2003 17:45:30 -0000	1.2
  +++ ApplicationUnavailable.html	24 Jan 2003 00:49:37 -0000	1.3
  @@ -43,7 +43,7 @@
   <table width="100%" border="0" cellspacing="0" cellpadding="0">
   	<tr bgcolor="#000000">
   		<td class="clsFooter" align="center" valign="bottom">&#169;2000-2002
  -		<a class="clsFooterLink" href="mailto:hship@users.sf.net">Howard Lewis Ship</a>.
  +		<a class="clsFooterLink" href="mailto:hlship@apache.org">Howard Lewis Ship</a>.
   		All rights reserved.
   		
   		</td>
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/pages/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/pages/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:50:08 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.4
  @@ -9,7 +9,7 @@
   Basic pages used for errors, stale links and stale sessions.  These can all be
   overriden in the application specification.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.20      +3 -1      jakarta-tapestry/junit/src/net/sf/tapestry/junit/TapestrySuite.java
  
  Index: TapestrySuite.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/TapestrySuite.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- TapestrySuite.java	17 Jan 2003 17:41:27 -0000	1.19
  +++ TapestrySuite.java	24 Jan 2003 00:49:38 -0000	1.20
  @@ -57,6 +57,7 @@
   import junit.framework.Test;
   import junit.framework.TestSuite;
   
  +import net.sf.tapestry.junit.enhance.TestClassFabricator;
   import net.sf.tapestry.junit.mock.MockTestCase;
   import net.sf.tapestry.junit.parse.SpecificationParserTest;
   import net.sf.tapestry.junit.parse.TemplateParserTest;
  @@ -106,6 +107,7 @@
           suite.addTestSuite(BindingsTestCase.class);
           suite.addTestSuite(TestPropertySource.class);
           suite.addTestSuite(ComponentTest.class);
  +        suite.addTestSuite(TestClassFabricator.class);
           suite.addTestSuite(MockTestCase.class);
   
           return suite;
  
  
  
  1.11      +7 -1      jakarta-tapestry/junit/src/net/sf/tapestry/junit/MockEngine.java
  
  Index: MockEngine.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/MockEngine.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- MockEngine.java	17 Jan 2003 17:41:27 -0000	1.10
  +++ MockEngine.java	24 Jan 2003 00:49:38 -0000	1.11
  @@ -59,6 +59,7 @@
   
   import javax.servlet.ServletException;
   
  +import net.sf.tapestry.IComponentClassEnhancer;
   import net.sf.tapestry.IComponentStringsSource;
   import net.sf.tapestry.IEngine;
   import net.sf.tapestry.IEngineService;
  @@ -224,6 +225,11 @@
       }
   
       public Object getGlobal()
  +    {
  +        return null;
  +    }
  +
  +    public IComponentClassEnhancer getComponentClassEnhancer()
       {
           return null;
       }
  
  
  
  1.9       +2 -3      jakarta-tapestry/junit/src/net/sf/tapestry/junit/BindingsTestCase.java
  
  Index: BindingsTestCase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/net/sf/tapestry/junit/BindingsTestCase.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- BindingsTestCase.java	17 Jan 2003 17:41:27 -0000	1.8
  +++ BindingsTestCase.java	24 Jan 2003 00:49:38 -0000	1.9
  @@ -576,8 +576,7 @@
           }
           catch (ApplicationRuntimeException ex)
           {
  -            checkException(ex, "Malformed OGNL");
  -            checkException(ex, "zip flob boff");
  +            checkException(ex, "Unable to parse expression 'zip flob boff'");
           }
       }
   
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/event/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/event/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	29 Jul 2002 21:11:17 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.2
  @@ -23,7 +23,7 @@
   objects to know about key lifecycle events regarding
   a page.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.16      +3 -2      jakarta-tapestry/framework/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/build.xml,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- build.xml	17 Jan 2003 17:40:27 -0000	1.15
  +++ build.xml	24 Jan 2003 00:49:38 -0000	1.16
  @@ -15,7 +15,8 @@
       <pathelement location="${lib.ext.dir}/org.apache.crimson.jar"/>
       <pathelement location="${lib.ext.dir}/${jakarta-oro.jar}"/>
       <pathelement location="${lib.ext.dir}/${ognl.jar}"/>
  -    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>
  +    <pathelement location="${lib.ext.dir}/${bsf.jar}"/>	
  +    <pathelement location="${lib.ext.dir}/${bcel.jar}"/>
     </path>
     
     <target name="init">
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/bean/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/bean/package.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- package.html	5 May 2002 21:04:01 -0000	1.1
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.2
  @@ -10,7 +10,7 @@
   the {@link net.sf.tapestry.IBeanProvider} interface, and 
   several interfaces and classes related to initializing helper beans.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/pool/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/pool/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	2 May 2002 21:37:14 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.5
  @@ -12,7 +12,7 @@
   {@link net.sf.tapestry.util.pool.Pool}.  Instead of discarding them, they
   are returned to the Pool.   The Pool class is threadsafe and reasonably efficient.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.3       +12 -9     jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/ShowTemplate.java
  
  Index: ShowTemplate.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/ShowTemplate.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ShowTemplate.java	17 Jan 2003 17:40:55 -0000	1.2
  +++ ShowTemplate.java	24 Jan 2003 00:49:38 -0000	1.3
  @@ -67,6 +67,7 @@
   import net.sf.tapestry.IRequestCycle;
   import net.sf.tapestry.ITemplateSource;
   import net.sf.tapestry.RequestCycleException;
  +import net.sf.tapestry.Tapestry;
   import net.sf.tapestry.parse.CloseToken;
   import net.sf.tapestry.parse.ComponentTemplate;
   import net.sf.tapestry.parse.LocalizationToken;
  @@ -104,7 +105,8 @@
       {
           return new IRender()
           {
  -            public void render(IMarkupWriter writer, IRequestCycle cycle) throws RequestCycleException
  +            public void render(IMarkupWriter writer, IRequestCycle cycle)
  +                throws RequestCycleException
               {
                   writeTemplate(writer, cycle);
               }
  @@ -166,7 +168,8 @@
   
               if (token.getType() == TokenType.OPEN)
               {
  -                boolean nextIsClose = (i + 1 < count) && (template.getToken(i + 1).getType() == TokenType.CLOSE);
  +                boolean nextIsClose =
  +                    (i + 1 < count) && (template.getToken(i + 1).getType() == TokenType.CLOSE);
   
                   write(writer, nextIsClose, (OpenToken) token);
   
  @@ -181,13 +184,13 @@
   
           writer.end(); // <pre>        
       }
  -    
  +
       /** @since 2.4 **/
  -    
  +
       private IComponent getInspectedComponent()
       {
  -        Inspector page = (Inspector)getPage();
  -        
  +        Inspector page = (Inspector) getPage();
  +
           return page.getInspectedComponent();
       }
   
  @@ -224,7 +227,7 @@
       private void write(IMarkupWriter writer, LocalizationToken token)
       {
           IComponent component = getInspectedComponent();
  -        
  +
           writer.begin("span");
           writer.attribute("class", "jwc-tag");
   
  @@ -268,7 +271,7 @@
       private void write(IMarkupWriter writer, boolean nextIsClose, OpenToken token)
       {
           IComponent component = getInspectedComponent();
  -        IEngineService service = getPage().getEngine().getService(IEngineService.DIRECT_SERVICE);
  +        IEngineService service = getPage().getEngine().getService(Tapestry.DIRECT_SERVICE);
           String[] context = new String[1];
   
           // Each id references a component embedded in the inspected component.
  
  
  
  1.3       +2 -2      jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	17 Jan 2003 17:40:55 -0000	1.2
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.3
  @@ -11,7 +11,7 @@
   it runs.  The {@link net.sf.tapestry.contrib.inspector.ShowInspector} component
   creates an icon on the page that raises the Inspector in a seperate window.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.3       +2 -2      jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/InspectorButton.java
  
  Index: InspectorButton.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/contrib/src/net/sf/tapestry/contrib/inspector/InspectorButton.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- InspectorButton.java	17 Jan 2003 17:40:55 -0000	1.2
  +++ InspectorButton.java	24 Jan 2003 00:49:38 -0000	1.3
  @@ -130,7 +130,7 @@
   
           Map symbols = new HashMap();
   
  -        IEngineService service = engine.getService(IEngineService.DIRECT_SERVICE);
  +        IEngineService service = engine.getService(Tapestry.DIRECT_SERVICE);
           Gesture g = service.buildGesture(cycle, this, null);
   
           symbols.put("URL", g.getURL());
  
  
  
  1.24      +3 -3      jakarta-tapestry/framework/src/net/sf/tapestry/form/Form.java
  
  Index: Form.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/form/Form.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- Form.java	17 Jan 2003 17:40:27 -0000	1.23
  +++ Form.java	24 Jan 2003 00:49:38 -0000	1.24
  @@ -587,9 +587,9 @@
           String serviceName = null;
   
           if (isDirect())
  -            serviceName = IEngineService.DIRECT_SERVICE;
  +            serviceName = Tapestry.DIRECT_SERVICE;
           else
  -            serviceName = IEngineService.ACTION_SERVICE;
  +            serviceName = Tapestry.ACTION_SERVICE;
   
           IEngine engine = cycle.getEngine();
           IEngineService service = engine.getService(serviceName);
  
  
  
  1.5       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/form/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/form/package.html,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- package.html	5 May 2002 21:04:02 -0000	1.4
  +++ package.html	24 Jan 2003 00:49:38 -0000	1.5
  @@ -14,7 +14,7 @@
   <p>Package {@link net.sf.tapestry.valid} contains more complex components that not only collect
   input, but validate it as well.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.8       +4 -0      jakarta-tapestry/eclipse/Tapestry-Mock.launch
  
  Index: Tapestry-Mock.launch
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/eclipse/Tapestry-Mock.launch,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Tapestry-Mock.launch	22 Jan 2003 16:48:15 -0000	1.7
  +++ Tapestry-Mock.launch	24 Jan 2003 00:49:38 -0000	1.8
  @@ -107,6 +107,10 @@
           <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
   &lt;runtimeClasspathEntry containerPath=&quot;JYTHON_DIR/jython.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;
   "/>
  +        <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  +&lt;runtimeClasspathEntry
  +    internalArchive=&quot;/jakarta-tapestry/lib/ext/bcel-5.0.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;
  +"/>
       </listAttribute>
       <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="jakarta-tapestry"/>
       <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dnet.sf.tapestry.enable-reset-service=true"/>
  
  
  
  1.7       +4 -0      jakarta-tapestry/eclipse/Tapestry-Junit.launch
  
  Index: Tapestry-Junit.launch
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/eclipse/Tapestry-Junit.launch,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Tapestry-Junit.launch	17 Jan 2003 17:39:27 -0000	1.6
  +++ Tapestry-Junit.launch	24 Jan 2003 00:49:38 -0000	1.7
  @@ -107,6 +107,10 @@
           <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
   &lt;runtimeClasspathEntry containerPath=&quot;JYTHON_DIR/jython.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;
   "/>
  +        <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  +&lt;runtimeClasspathEntry
  +    internalArchive=&quot;/jakarta-tapestry/lib/ext/bcel-5.0.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;
  +"/>
       </listAttribute>
       <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="jakarta-tapestry"/>
       <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Dnet.sf.tapestry.enable-reset-service=true"/>
  
  
  
  1.119     +9 -3      jakarta-tapestry/web/new.html
  
  Index: new.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/web/new.html,v
  retrieving revision 1.118
  retrieving revision 1.119
  diff -u -r1.118 -r1.119
  --- new.html	22 Jan 2003 16:51:19 -0000	1.118
  +++ new.html	24 Jan 2003 00:49:39 -0000	1.119
  @@ -18,13 +18,19 @@
           arrays of objects and scalars</li>
   <LI>Upgrade demos to deploy into JBoss 3.0.4</LI>   
   <li>Merge in changes from Tapestry 2.3</li>
  -<li><code>&lt;binding&gt;</code> elements may now specify the expression as the parsed data</li> 
  +<li><code>&lt;binding&gt;</code> elements may now specify the expression as the parsed data
  +instead of the expression attribute</li> 
   <li>The template extension may now be overriden using the configuration property <code>net.sf.tapestry.template-extension</code>         
  -
  +<li>Added support for declarative transient and persistent properties via
  +<code>&lt;property-specification;&gt;</code> element in page and component specifications.  Tapestry
  +will create (on the fly) a subclass with
  +the necessary accessor methods and fields, as well as any necessary notification and
  +cleanup methods. </li>
   </ul>
   
   <pre>
   [ 594878 ] Deploy Tapestry into JBoss 3.0.4
  +[ 672743 ] Pages Implementing Listeners cause NPE
   </pre>
   
   <h3>Release 2.4-alpha-1</h3>
  
  
  
  1.3       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/callback/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/callback/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	16 May 2002 20:10:04 -0000	1.2
  +++ package.html	24 Jan 2003 00:49:39 -0000	1.3
  @@ -18,7 +18,7 @@
   <p>Another example use would be to collect billing and shipping information as part of
   an e-commerce site's checkout wizard.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.14      +5 -5      jakarta-tapestry/doc/src/ContributorsGuide/ContributorsGuide.xml
  
  Index: ContributorsGuide.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/doc/src/ContributorsGuide/ContributorsGuide.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- ContributorsGuide.xml	20 Jan 2003 15:06:03 -0000	1.13
  +++ ContributorsGuide.xml	24 Jan 2003 00:49:39 -0000	1.14
  @@ -1016,9 +1016,9 @@
   
   <programlisting>
   <![CDATA[
  -  <assert name="Session Attribute"
  -    expression='request.session.getAttribute("app/Home/message").equals("Changed")'
  -  />				
  +  <assert name="Session Attribute">
  +  request.session.getAttribute("app/Home/message").equals("Changed")
  +  </assert>				
   ]]>
   </programlisting>
   
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/components/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/components/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:42:57 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:39 -0000	1.4
  @@ -9,7 +9,7 @@
   <p>Basic, fundamental components used to construct more complex components, or pages.  
   These components are independant of any particular markup language.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.3       +1 -1      jakarta-tapestry/examples/Tutorial/context/redirect-target.html
  
  Index: redirect-target.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Tutorial/context/redirect-target.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- redirect-target.html	17 Jan 2003 17:45:30 -0000	1.2
  +++ redirect-target.html	24 Jan 2003 00:49:39 -0000	1.3
  @@ -34,7 +34,7 @@
   </tr>
   </table>
   <p>
  -&copy; 2000-2002 <a href="mailto:hship@users.sf.net">Howard M. Lewis Ship</a>.
  +&copy; 2000-2002 <a href="mailto:hlship@apache.org">Howard M. Lewis Ship</a>.
   
   
   </body>
  
  
  
  1.6       +1 -1      jakarta-tapestry/framework/src/net/sf/tapestry/listener/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/listener/package.html,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- package.html	16 May 2002 20:10:03 -0000	1.5
  +++ package.html	24 Jan 2003 00:49:39 -0000	1.6
  @@ -33,7 +33,7 @@
   @see net.sf.tapestry.engine.AbstractEngine#getListeners()
   @since 1.0.2
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/xml/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/xml/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:53:59 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:39 -0000	1.4
  @@ -11,7 +11,7 @@
   <p>Base classes for streamlining the process of parsing an XML document.  This is primarily 
   used with a validating parser, where the DTD is stored within the classpath.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>
  
  
  
  1.4       +2 -2      jakarta-tapestry/framework/src/net/sf/tapestry/util/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/net/sf/tapestry/util/package.html,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- package.html	2 May 2002 17:53:58 -0000	1.3
  +++ package.html	24 Jan 2003 00:49:39 -0000	1.4
  @@ -9,7 +9,7 @@
   
   <p>A general set of resuable classes and utilities for creating Internet and XML applications.
   
  -@author Howard Lewis Ship <a href="mailto:hship@users.sf.net">hship@users.sf.net</a>
  +@author Howard Lewis Ship <a href="mailto:hlship@apache.org">hlship@apache.org</a>
   
   </body>
   </html>