A document has been updated:

http://cocoon.zones.apache.org/daisy/documentation/688.html

Document ID: 688
Branch: main
Language: default
Name: Creating a Generator (unchanged)
Document Type: Document (unchanged)
Updated on: 9/11/05 11:58:33 AM
Updated by: Geoff Howard

A new version has been created, state: publish

Parts
=====
Content
-------
This part has been updated.
Mime type: text/xml (unchanged)
File name:  (unchanged)
Size: 15485 bytes (previous version: 15565 bytes)
Content diff:
(57 equal lines skipped)
    </p>
    
    <p>To realize these requirements we have to find a bean, and then "render 
it".
--- In this case the XML rendering of the bean will be recursive.  The general
--- approach will use Java's reflection mechanisms, and only worry about
--- properties.  There will be a certain amount of risk involved with a complex 
bean
--- that includes references to other beans in that if you have two beans 
referring
--- to each other you will have an infinite loop.  Detecting these is outside 
the
--- scope of what we are trying to do, and that is generally bad design anyway 
so we
--- won't worry too much about it.  Yes there is overhead with the beans
--- Introspector but we are writing for the general case.</p>
+++ In this case the XML rendering of the bean will be recursive. The general
+++ approach will use Java's reflection mechanisms, and only worry about 
properties.
+++ There will be a certain amount of risk involved with a complex bean that
+++ includes references to other beans in that if you have two beans referring 
to
+++ each other you will have an infinite loop. Detecting these is outside the 
scope
+++ of what we are trying to do, and that is generally bad design anyway so we 
won't
+++ worry too much about it. Yes there is overhead with the beans Introspector 
but
+++ we are writing for the general case.</p>
    
    <p>To set up our generator, we need to use a serializer that shows us what 
the
    results are, so we will set up our sitemap to use our generator like 
this:</p>
(6 equal lines skipped)
    
    <p>Even though it is generally bad design to have a static anything in a 
Cocoon
    application we are going to use a helper class called "BeanPool" with the 
get()
--- and put() methods that are familiar from the HashMap.  So that it is easier 
for
+++ and put() methods that are familiar from the HashMap. So that it is easier 
for
    you to change the behavior of the BeanGenerator, we will provide a nice
    protected method called <tt>findBean()</tt> which is meant to be overridden 
with
    something more robust.</p>
(48 equal lines skipped)
    </pre>
    
    <p>As you can see, we have our simplified <tt>findBean()</tt> method which 
can
--- be replaced with something more robust later.  All you need to do to 
populate
--- the BeanPool is to call the <tt>BeanPool.put(String key, Object bean)</tt>
--- method from somewhere else.</p>
+++ be replaced with something more robust later. All you need to do to 
populate the
+++ BeanPool is to call the <tt>BeanPool.put(String key, Object bean)</tt> 
method
+++ from somewhere else.</p>
    
    <h3>Setting up to Generate</h3>
    
(11 equal lines skipped)
    
    <p>What we did is call the setup method from AbstractGenerator which 
populates
    some class fields for us (like the <tt>source</tt> field), then we tried to 
find
--- the bean using the key provided.  If the bean is <tt>null</tt>, then we 
follow
+++ the bean using the key provided. If the bean is <tt>null</tt>, then we 
follow
    the principle of least surprise and throw the <tt>ResourceNotFoundException
    </tt>so the Sitemap knows that we simply don't have the bean available 
instead
--- of generating some lame 500 server error.  That's all we have to do to set 
up
--- this particular Generator.  Oh, and since we do have the <tt>m_bean</tt> 
field
--- populated we do want to clean up after ourselves properly.  Let's add the
+++ of generating some lame 500 server error. That's all we have to do to set up
+++ this particular Generator. Oh, and since we do have the <tt>m_bean</tt> 
field
+++ populated we do want to clean up after ourselves properly. Let's add the
    recycle() method from Recyclable so that we don't give an old result when a 
bean
    can't be found:</p>
    
(7 equal lines skipped)
    
    <h3>The Caching Clues</h3>
    
--- <p>We are going to make the caching for the BeanGenerator really simple. 
--- Ideally we would have something that listens for changes and invalidates the
--- SourceValidity if there is a change to the bean we are rendering.  
Unfortunately
+++ <p>We are going to make the caching for the BeanGenerator really simple. 
Ideally
+++ we would have something that listens for changes and invalidates the
+++ SourceValidity if there is a change to the bean we are rendering. 
Unfortunately
    that is outside our scope, and we will set up the key so that it never 
expires
--- unless it is done manually.  Since we are using the source property from the
+++ unless it is done manually. Since we are using the source property from the
    Sitemap as our key, let's just use that as our cache key:</p>
    
    <pre>    public Serializable getKey()
(11 equal lines skipped)
    </pre>
    
    <p>Using this approach is a bit naive in the sense that it is very possible 
that
--- the beans will have changed.  We could use an ExpiresValidity instead to 
make
+++ the beans will have changed. We could use an ExpiresValidity instead to make
    things a bit more resilient to change, but that is an excersize for you, 
dear
    reader.</p>
    
    <h3>Generating Output</h3>
    
--- <p>Now that we have our bean, we are ready to generate our output.  The
+++ <p>Now that we have our bean, we are ready to generate our output. The
    AbstractXMLProducer base class (AbstractGenerator inherits from that) 
stores the
--- target in a class field named <tt>contentHandler</tt>.  Simple enough.  
We'll
+++ target in a class field named <tt>contentHandler</tt>. Simple enough. We'll
    start by implementing the generate() method, but we already know we need to
--- handle beans differently than the standard String and primitive types.  So 
let's
--- stub out the method we will use for recursive serialization.  Here we 
go:</p>
+++ handle beans differently than the standard String and primitive types. So 
let's
+++ stub out the method we will use for recursive serialization. Here we go:</p>
    
    <pre>    public void generate()
        {
(5 equal lines skipped)
        }
    </pre>
    
--- <p>All we did was call the start and end document for the whole XML 
Document. 
--- That is enough for a basic XML document with no content.  The
+++ <p>All we did was call the start and end document for the whole XML 
Document.
+++ That is enough for a basic XML document with no content. The
    <tt>renderBean()</tt> method is where the magic happens:</p>
    
    <pre>    public void renderBean(String root, Object bean)
(17 equal lines skipped)
        }
    </pre>
    
--- <p>So far we created the root element and started iterating over the
--- properties.  Our root element consists of a namespace a name and a qName.  
Our
--- implementation is using the <tt>source</tt> for the initial root element so 
as
--- long as we never have any special characters like a colon (':') we should be
--- OK.  Without going through the individual properties, a java.awt.Dimension
--- object with a source of "dim" will be redered like this:</p>
+++ <p>So far we created the root element and started iterating over the 
properties.
+++ Our root element consists of a namespace a name and a qName. Our 
implementation
+++ is using the <tt>source</tt> for the initial root element so as long as we 
never
+++ have any special characters like a colon (':') we should be OK. Without 
going
+++ through the individual properties, a java.awt.Dimension object with a 
source of
+++ "dim" will be redered like this:</p>
    
    <pre>&lt;dim:dim xmlns:dim="java:java.awt.Dimension"/&gt;
    </pre>
(30 equal lines skipped)
    </pre>
    
    <p>This method is a little more complex in that we have to figure out if the
--- property is readable, and is a type we can handle.  In this case, we don't 
read
+++ property is readable, and is a type we can handle. In this case, we don't 
read
    indexed properties (if you want to support that, you'll have to extend this 
code
--- to do that), and we don't read any properties where there is no read 
method.  We
--- use the property name for the elements surrouding the property values.  We 
get
--- the value, and then we call the start and end elements for the property.  
Inside
+++ to do that), and we don't read any properties where there is no read 
method. We
+++ use the property name for the elements surrouding the property values. We 
get
+++ the value, and then we call the start and end elements for the property. 
Inside
    of the calls, we determine if the item is a bean, and if so we render the 
bean
    using the renderBean method (the recursive aspect); otherwise we render the
--- content as text as long as it is not null.  Once the <tt>isBean()</tt> 
method is
+++ content as text as long as it is not null. Once the <tt>isBean()</tt> 
method is
    implemented, our Dimension example above will produce the following 
result:</p>
    
    <pre>&lt;dim:dim xmlns:dim="java:java.awt.Dimension"&gt;
(22 equal lines skipped)
    </pre>
    
    <p>The isBean() method will treat all primitives, Strings, Dates, and 
anything
--- in "java.lang" as value objects.  This captures the boxed versions of 
primitives
--- as well as the unboxed versions.  Everything else is treated as a bean.</p>
+++ in "java.lang" as value objects. This captures the boxed versions of 
primitives
+++ as well as the unboxed versions. Everything else is treated as a bean.</p>
    
    <h2>Summary</h2>
    
    <p>Generators aren't too difficult to write, but the tricky parts are there 
due
--- to namespaces.  As long as you are familiar with the SAX API you should not 
have
--- any problems.  The complexity in our generator is really from the reflection
--- logic used to discover how to render an object.  You might ask why we 
didn't use
--- the XMLEncoder in the java.beans package.  The answer has to do with the 
fact
+++ to namespaces. As long as you are familiar with the SAX API you should not 
have
+++ any problems. The complexity in our generator is really from the reflection
+++ logic used to discover how to render an object. You might ask why we didn't 
use
+++ the XMLEncoder in the java.beans package. The answer has to do with the fact
    that the facility is based on IO streams, and can't be easily adapted to XML
--- streams.  At any rate, we have something that can work with a wide range of
--- classes.  Our XML is easy to understand.  Here is a snippet from a more 
complex
+++ streams. At any rate, we have something that can work with a wide range of
+++ classes. Our XML is easy to understand. Here is a snippet from a more 
complex
    example:</p>
    
    <pre>&lt;line:line xmlns:line="java:com.mycompany.shapes.Line"&gt;
(13 equal lines skipped)
    &lt;/line:line&gt;
    </pre>
    
--- <p>Our therhetical line object contained a name and two java.awt.Point 
objects
--- which in turn had an x and a y property.  It is easier to understand when 
you
--- have domain specific beans that are backed to a database.  Nevertheless, we 
have
+++ <p>Our theoretical line object contained a name and two java.awt.Point 
objects
+++ which in turn had an x and a y property. It is easier to understand when you
+++ have domain specific beans that are backed to a database. Nevertheless, we 
have
    a generator that satisfies a general purpose and can be extended later on to
    support our needs as they change.</p>
    
(2 equal lines skipped)


Fields
======
no changes

Links
=====
no changes

Custom Fields
=============
no changes

Collections
===========
no changes