cocoon-docs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject [DAISY] Created: Creating a Reader
Date Thu, 25 Aug 2005 17:58:59 GMT
A new document has been created.

Document ID: 681
Branch: main
Language: default
Name: Creating a Reader
Document Type: Document
Created: 8/25/05 5:58:53 PM
Creator (owner): Berin Loritsch
State: publish


Mime type: text/xml
Size: 5967 bytes

<h1>Creating a Reader</h1>

<p>Readers are the components that send you a stream without the XML processing
that normally happens in a pipeline.  Cocoon already comes with some readers out
of the box such as your FileReader which serializes files from your webapp
context.  What if you need something that doesn't come from the file system? 
What if you need to create content on the fly but the XML processing gets in the
way?  That's where the Reader comes to play.  Even though there is a
DatabaseReader in the Cocoon's SQL block, we are going to go through the process
of creating a cacheable database reader here.</p>

<p>In the sitemap we use the reader we are going to develop like this:</p>

<pre>&lt;map:match pattern="attachment/*"&gt;
  &lt;map:read type="db-attachments" src="{1}"/&gt;

<p>The sitemap snippet above matches anything in the attachment path followed by
the ID for the attachment.  It then passes the ID into the <tt>src</tt>
attribute for our reader.  Why not include the nice neat little extension for
the file after the ID?  We actually have a very good reason: Microsoft.  If you
recall from the <a href="daisy:674">SitemapOutputComponent Contracts</a> page,
Internet Explorer likes to pretend its smarter than you are.  If you have a file
extension on the URL that IE knows, it will ignore your mime-type settings that
you provide.  However, if you don't provide any clues then IE has to fall back
to respecting the standard.</p>

<h2>How Does the Sitemap Treat a Reader?</h2>

<p>A Sitemap fills two of the core contracts with the Sitemap.  It is both a
SitemapModelComponent and a SitemapOutputComponent.  You <em>can</em> make it
CacheableProcessingComponent as well, which will help reduce the load on your
database by avoiding the need to retrieve your attachments all the time.  In
fact, unless you have a good reason not to, you should always make your
components cacheable just for the flexibility in deployment later.  I recommend
you read the articles on the core contracts to understand where to find the
resources you need.</p>

<p>A sitemap will fulfill all its core contracts first.  It will then query the
reader using the <tt>getLastModified()</tt> method.  The results of that method
will be added to the response header for browser caching purposes--although it
is only done for the CachingPipeline.  Lastly, the sitemap will call the
<tt>generate()</tt> method to create and send the results back to the client. 
It's a one stop shop, and because the Reader is both a SitemapModelComponent and
a SitemapOutputComponent it is the beginning and the end of your pipeline.</p>

<p>Considering the order in which the processing happens, the sooner you can
send a response to the Sitemap because of a failure the better.</p>

<h2>ServiceableReader: A Good Start</h2>

<p>The ServiceableReader provides a good basis for building our database bound
AttachmentReader.  The ServiceableReader implements the Recyclable, LogEnabled
and Serviceable interfaces and captures some of the information you will need
for you.  We will need these three interfaces to get a reference to the
DataSourceComponent, our Logger, and to clean up our request based artifacts. 
You might want to implement the Parameterizable or Configurable interfaces if
you want to decide which particular database we will be hitting in your own
code.  For now, we are going to hard code the information.</p>

<h3>The Skeleton</h3>

<p>Our skeleton code will look like this:</p>

<pre>import org.apache.avalon.excalibur.datasource.DataSourceComponent;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.reading.ServiceableReader;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.TimeStampValidity;
import org.xml.sax.SAXException;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Map;

public class AttachmentReader extends ServiceableReader implements CacheableProcessingComponent,
    private static final int BUFFER = 1024;
    public static String DB_RESOURCE_NAME = "ourdb"; // warning: static database table name

    // ... skip many methods covered later

    public void setup( SourceResolver sourceResolver, Map model, String src, Parameters params
        throws IOException, ProcessingException, SAXException
        // ... skip setup code for now

    public void generate() throws IOException, SAXException, ProcessingException
        // ... skip generate code for now

<p>If you'll notice we added the Disposable interface to the contract as well. 
This is so that we can be good citizens and release our components when we are
done with them.  Anything pooled needs to be released.  While it's probably safe
to treat your DataSourceComponent and your ServiceManager as singletons in the
system, we still want to be responsible.  First things first, let's get our
DataSourceComponent and hold on to it as long as this Reader is around.  To do
this we will need to add two more class fields:</p>

<pre>    private DataSourceComponent datasource;
    private ServiceSelector dbselector;

<p>Now we are going to override the <tt>service()</tt> method and implement
<tt>dispose()</tt> method to get and cleanup after ourselves.</p>


The document belongs to the following collections: documentation

View raw message