You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/08/29 05:13:52 UTC

svn commit: r437926 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/structure/ site/ site/apt/guide/ test/java/org/apache/tapestry/...

Author: hlship
Date: Mon Aug 28 20:13:52 2006
New Revision: 437926

URL: http://svn.apache.org/viewvc?rev=437926&view=rev
Log:
Streamline the MarkupWriter interface.
Add initial documentation concerning configuration and component class reloading.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/AttributePageElement.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
    tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java Mon Aug 28 20:13:52 2006
@@ -34,13 +34,16 @@
     /**
      * Begins a new element as a child of the current element. The new element becomes the current
      * element. The new Element is returned and can be directly manipulated (possibly at a later
-     * date).
+     * date). Optionally, attributes for the new element can be specified directly.
      * 
      * @param name
      *            the name of the element to create
+     * @param attributes
+     *            an even number of values, alternating names and values
      * @return the new DOM Element node
+     * @see #attributes(Object[])
      */
-    Element element(String name);
+    Element element(String name, Object... attributes);
 
     /**
      * Ends the current element. The new current element will be the parent element. Returns the new
@@ -70,20 +73,10 @@
     void comment(String text);
 
     /**
-     * Adds an attribute to the current element. If an attribute with the given name has already
-     * been added to the element, then the new value is <strong>ignored</strong>
-     * <p>
-     * TODO: Overrides for primitive types?
-     * 
-     * @param name
-     *            the name of the attribute to add
-     * @param value
-     *            the value to be stored as the attribute
+     * Adds a series of attributes and values. Null values are quietly skipped. If a name already
+     * has a value, then the new value is <em>ignored</em>.
      */
-    void attribute(String name, String value);
-
-    /** Adds a series of attributes and values. */
-    void attributes(String... namesAndValues);
+    void attributes(Object... namesAndValues);
 
     /** Converts the collected markup into an XML stream, sent to the writer. */
     void toXML(PrintWriter writer);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java Mon Aug 28 20:13:52 2006
@@ -69,14 +69,7 @@
         write("\n");
     }
 
-    public void attribute(String name, String value)
-    {
-        ensureCurrentElement();
-
-        _current.addAttribute(name, value);
-    }
-
-    public void attributes(String... namesAndValues)
+    public void attributes(Object... namesAndValues)
     {
         ensureCurrentElement();
 
@@ -84,10 +77,15 @@
 
         while (i < namesAndValues.length)
         {
-            String name = namesAndValues[i++];
-            String value = namesAndValues[i++];
+            // name should never be null.
+
+            String name = namesAndValues[i++].toString();
+            Object value = namesAndValues[i++];
 
-            _current.addAttribute(name, value);
+            if (value == null)
+                continue;
+
+            _current.addAttribute(name, value.toString());
         }
 
     }
@@ -98,12 +96,14 @@
             throw new IllegalStateException(ServicesMessages.markupWriterNoCurrentElement());
     }
 
-    public Element element(String name)
+    public Element element(String name, Object... namesAndValues)
     {
         if (_current == null)
             _current = _document.newRootElement(name);
         else
             _current = _current.element(name);
+
+        attributes(namesAndValues);
 
         _currentText = null;
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/AttributePageElement.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/AttributePageElement.java?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/AttributePageElement.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/AttributePageElement.java Mon Aug 28 20:13:52 2006
@@ -36,7 +36,7 @@
 
     public void render(MarkupWriter writer, RenderQueue queue)
     {
-        writer.attribute(_name, _value);
+        writer.attributes(_name, _value);
     }
 
     @Override

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt?rev=437926&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/conf.apt Mon Aug 28 20:13:52 2006
@@ -0,0 +1,62 @@
+ ---
+ Configuring Tapestry
+ ---
+ 
+Configuring Tapestry
+
+  Tapestry runs on top of the standard Java Servlet API.  To the servlet container,
+  such as Tomcat, Tapestry appears to be a <servlet filter>.  
+  
+* web.xml
+
+  The majority of configuration occurs inside the servlet deployment descriptor,
+  WEB-INF/web.xml.
+  
+  Most of the configuration is boilerplate; the same for all applications.
+  
+  The application specific configuration is to identify the root application package.
+  Tapestry uses this package name to locate your page and component classes.
+  
+  Page classes must go in the pages sub-package, and components must go in the
+  components sub-package.
+  
+  You specify the root package as a context parameter:
+  
++----+
+<!DOCTYPE web-app
+      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+      "http://java.sun.com/dtd/web-app_2_3.dtd">
+<web-app>
+    <display-name>My Tapestry Application</display-name>
+    <context-param>
+        <param-name>tapestry.app-package</param-name>
+        <param-value>org.example.myapp</param-value>
+    </context-param>
+    <filter>
+        <filter-name>app</filter-name>
+        <filter-class>org.apache.tapestry.TapestryFilter</filter-class>
+    </filter>
+    <filter-mapping>
+        <filter-name>app</filter-name>
+        <url-pattern>/</url-pattern>
+    </filter-mapping>
+</web-app>
++----+  
+
+  You may name the filter whatever you want, though "app" is a common convention.
+  
+  In this example, page classes will be stored in the org.example.myapp.pages package (or in sub-packages below).
+  Likewise, component classes will be stored in the org.example.myapp.components package.
+  
+* Tapestry IoC Configuration
+
+  Most other configuration occurs inside your application's module builder class.  The application module builder
+  will often define new services, provide overrides of services, or make contributions to service configurations.
+  
+  Tapestry looks for a module builder class in the services package (under the root package). It capitalizes
+  the \<filter-name\> and appends "Module".  In the previous example, the module builder class
+  would be org.example.myapp.services.AppModule.
+  
+  If such a class exists, it is added to the IoC Registry. It is not an error for your application to not have a module, though
+  any non-trivial application will likely have one.
+  
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/dom.apt Mon Aug 28 20:13:52 2006
@@ -43,7 +43,9 @@
   allows the majority of code to treat the generation of output as a stream. In fact,
   MarkupWriter is more like a cursor into the DOM tree.
   
-  Once all rendering is complete, the DOM tree is streamed to the client.  
+  Once all rendering is complete, the DOM tree is streamed to the client.  Planned enhancements
+  will control output formatting, including pretty-printing and/or output compression (elimination
+  of all unnecessary whitespace).
   
 DOM Classes
 
@@ -76,42 +78,81 @@
   with the specified name already exists, then then the new value is ignored. This has implications when
   different pieces of code try to add attributes to an Element ... the first to add an attribute will "win"
   
+  Not yet implemented are some basic methods for manipulating the DOM after it is built. Plans are to add
+  a few methods for re-parenting DOM nodes into new elements. In addition, some searching methods may be added.
   
   
-  
-MarkupWriter
+{{{../apidocs/org/apache/tapestry/MarkupWriter.html}MarkupWriter}}
 
   The MarkupWriter interface allows the structure of the document to be built while maintaining a streaming metaphor.
   
-  Calls to begin() create a new element within the tree.  Calls to write(), writeln() and writef() write text nodes
-  within the current element.  Every call to begin() should be matched with a call to end(), which is used to move
-  the current node up one level. 
-  
-  Within an element, the attributes() method allows a series of attribute/value pairs to be written out.  A simple example:
-  
+* element() and end()
+
+  Calls to element() create a new element within the tree, and may provide attributes for the new element as well.  
+  Calls to write(), writeln() and writef() write text nodes
+  within the current element.  <Every call to element() should be matched with a call to end()>, which is used to move
+  the current node up one level.
+
+    
 +-----+
 
-  writer.begin("img");
-  writer.attributes("src", "icon.png", "width", "20", "height", "20", alt, "*");
+  writer.element("img", "src", "icon.png", "width", 20, "height", 20, alt, "*");
   writer.end();
 +-----+
   
-  Noet that end() must be called here, even though the \<img\> element is empty (has no body).  If the call to
-  end() is omitted, then later element created by begin() will be nested <inside> the \<img\> element, which is not
-  desired.
+  Note that end() must be called here, even though the \<img\> element is empty (has no body).  If the call to
+  end() is omitted, then later elements created by calls to element() will be 
+  nested <inside> the \<img\> element, which is not desired.
   
-  Again, <<every call to begin() must be matched with a call to end()>>.
+  Again, <<every call to element() must be matched with a call to end()>>:
+
   
 +-----+
-  writer.begin("select");
-  writer.attribute("name", "choice");
+  writer.element("select", "name", "choice");
   
   for (String name : optionsNames)
   {
-    writer.begin("option");
+    write.element("option");
     writer.write(name);
     writer.end();
   }
   
   writer.end();
-+-------+
\ No newline at end of file
++-------
+    
+
+* attributes()
+  
+  Adds additional name/value pairs to the current element.
+ 
+  When a value is null, no attribute is added.
+  
+  When a new name conflicts with an existing name, the new value is ignored. This gives precedence to the first value specified
+  for an attribute over any subsequent value.
+  
+* write()
+
+  The write() method writes text inside the current element.
+  
+  <<TODO: write() will eventually filter character data, converting certain characters into XML entities.  This is not yet implemented.>>
+  
+* writeln()
+
+  Writes a blank line, which is useful for neatness.
+  
+  <<TODO: This may go away in the future, once output pretty-printing and/or compression is implemented.>>
+  
+* writef()
+
+  The writef() method formats an number of arguments.  It uses a java.util.Formatter.  It is a convience for formatting that ultimately
+  invokes write().
+  
+* comment()
+
+  Adds an XML comment.  The comment delimiters will be supplied by Tapestry:
+  
++----+
+
+  writer.comment("Start of JS Menu code");
+  
++----+

Added: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt?rev=437926&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/reload.apt Mon Aug 28 20:13:52 2006
@@ -0,0 +1,50 @@
+ ---
+ Class and Template Reloading
+ ---
+ 
+Class and Template Reloading
+
+  One of the great new features of Tapestry 5 is automatic reloading of changed classes and templates.
+  
+  In previous versions of Tapestry, reloading of templates was supported in development mode only. Reloading of classes
+  required a restart of the servlet container (or a redeploy of the web application).
+  
+  In Tapestry 5, <page and component> classes will automatically reload when changed.  Likewise, changes to
+  component templates  and other related resources will also be picked up immediately.
+  
+  <Note: eventually, there will be some configuration to control how often changes are checked for. Currently it is forced
+  to operate on virtually every request, which is fine for development but not appropriate for production.>
+  
+Page and Component Packages
+
+  Only page and component classes are subject to reload.
+  
+  Reloading is based on package name; the packages that are reloaded are derived from the {{{conf.html}application configuration}}.
+  
+Class Loader Issues
+
+  Tapestry uses an extra class loader to load page and component classes.
+  
+  When a change to an underlying Java class file is detected, Tapestry discards the class loader and any pooled page instances.
+  
+  You should be careful to not hold any references to Tapestry pages or components in other code, such as Tapestry IoC services. 
+  Holding such references can cause significant memory leaks, as they can prevent the class loader from being reclaimed by the garbage
+  collector.
+  
+ClassCastExceptions
+
+  Tapestry's class loader architecture can cause minor headaches when you make use of a services layer, or any time that you pass
+  component instances to objects that are not themselves components.
+  
+  You will often see a ClassCastException.  This is because the same class name, say org.example.myapp.pages.Start, exists as two different
+  class instances.  One class instance is loaded by the web application's default class loader.  A second class 
+  instance has been loaded <and transformed> by Tapestry's reloading class loader.
+  
+  Ordinary classes, such as Tapestry IoC Services, will be loaded by the default class loader and expect instances to be
+  loaded by the same class loader (or a parent).
+  
+  The solution to this problem is to introduce an interface; the component class will implement the interface, the service will
+  expect an instance of the interface, rather than a specific type. 
+  
+  It is important that the interface be loaded by the default class loader, it should not be in the pages or components
+  package, but instead be in another package, such as services.
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/request.apt Mon Aug 28 20:13:52 2006
@@ -13,7 +13,7 @@
 Tapestry Filter
 
   All incoming requests originate with the TapestryFilter, which is configured
-  inside the application's web.xml.
+  inside the application's {{{conf.html}web.xml}}.
   
   The TapestryFilter is responsible for a number of startup and initialization
   functions.
@@ -21,11 +21,7 @@
   When it receives a request, the TapestryFilter obtains the
   {{{../apidocs/org/apache/tapestry/services/HttpServletRequestHandler.html}tapestry.HttpServletRequestHandler}} 
   service, and invokes its service() method. 
-  
-  <<TODO: How does the TF identify which requests it will process, and which are
-  for static content files?  Or is that a function of a filter within the pipeline.>>
-  
-  
+    
 HttpServletRequestHandler Pipeline
 
   This pipeline performs initial processing of the request. It can be extended
@@ -51,6 +47,12 @@
    is necessary to support non-servlet applications, such as portlet applications. Where other code and services within
    Tapestry require access to information in the request, such as query parameters, that information is obtained from the
    WebRequest (or WebResponse) objects.
+   
+   The pipeline includes two built-in filters.  One filter is responsible for {{{reload.html}class and template reloading}}.
+   
+   A second filter detects incoming requests that are for static resources (images, stylesheets, static HTML files, etc.)
+   within the context; such requests are
+   processed by the servlet container directly.
    
    <<TODO: Describe request dispatch, once that is understood.>>
    

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Mon Aug 28 20:13:52 2006
@@ -65,8 +65,10 @@
         </menu>
 
         <menu name="Internals Guide">
+            <item name="Configuration" href="guide/conf.html"/>
             <item name="Request Processing" href="guide/request.html"/>
-            <item name="DOM" href="guide/dom.html"/>
+            <item name="DOM" href="guide/dom.html"/>
+            <item name="Class Reloading" href="guide/reload.html"/>
         </menu>
                 
         ${reports}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java?rev=437926&r1=437925&r2=437926&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java Mon Aug 28 20:13:52 2006
@@ -49,14 +49,6 @@
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void attribute_with_no_current_element()
-    {
-        MarkupWriter w = new MarkupWriterImpl();
-
-        w.attribute("fail", "now");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
     public void attributes_with_no_current_element()
     {
         MarkupWriter w = new MarkupWriterImpl();
@@ -81,7 +73,7 @@
 
         Element root = w.element("root");
 
-        w.attribute("foo", "bar");
+        w.attributes("foo", "bar");
 
         w.write("before child");
 
@@ -98,6 +90,17 @@
         assertEquals(
                 w.toString(),
                 "<root foo=\"bar\" gnip=\"gnop\">before child<nested>inner text</nested>after child</root>");
+    }
+
+    @Test
+    public void element_with_attributes()
+    {
+        MarkupWriter w = new MarkupWriterImpl();
+
+        w.element("img", "src", "foo.png", "width", 20, "height", 20);
+        w.end();
+
+        assertEquals(w.toString(), "<img height=\"20\" src=\"foo.png\" width=\"20\"/>");
     }
 
     @Test