Return-Path: Delivered-To: apmail-cocoon-docs-archive@www.apache.org Received: (qmail 10981 invoked from network); 25 Aug 2005 18:01:35 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 25 Aug 2005 18:01:35 -0000 Received: (qmail 48643 invoked by uid 500); 25 Aug 2005 18:01:35 -0000 Delivered-To: apmail-cocoon-docs-archive@cocoon.apache.org Received: (qmail 48612 invoked by uid 500); 25 Aug 2005 18:01:34 -0000 Mailing-List: contact docs-help@cocoon.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: docs@cocoon.apache.org List-Id: Delivered-To: mailing list docs@cocoon.apache.org Received: (qmail 48599 invoked by uid 99); 25 Aug 2005 18:01:34 -0000 X-ASF-Spam-Status: No, hits=0.2 required=10.0 tests=NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [207.7.158.203] (HELO cocoon.zones.apache.org) (207.7.158.203) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 25 Aug 2005 11:01:34 -0700 Message-ID: <25248524.1124992739682.JavaMail.daisy@cocoon.zones.apache.org> Date: Thu, 25 Aug 2005 17:58:59 +0000 (GMT+00:00) From: daisy@cocoon.zones.apache.org To: docs@cocoon.apache.org Subject: [DAISY] Created: Creating a Reader Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N A new document has been created. http://cocoon.zones.apache.org/daisy/documentation/681.html 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 Parts =3D=3D=3D=3D=3D Content ------- Mime type: text/xml Size: 5967 bytes Content:

Creating a Reader

Readers are the components that send you a stream without the XML proces= sing that normally happens in a pipeline.=C2=A0 Cocoon already comes with some r= eaders out of the box such as your FileReader which serializes files from your webapp context.=C2=A0 What if you need something that doesn't come from the file s= ystem?=C2=A0 What if you need to create content on the fly but the XML processing gets i= n the way?=C2=A0 That's where the Reader comes to play.=C2=A0 Even though there i= s a DatabaseReader in the Cocoon's SQL block, we are going to go through the pr= ocess of creating a cacheable database reader here.

In the sitemap we use the reader we are going to develop like this:

<map:match pattern=3D"attachment/*">
  <map:read type=3D"db-attachments" src=3D"{1}"/>
</map:match>

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

How Does the Sitemap Treat a Reader?

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

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

Considering the order in which the processing happens, the sooner you ca= n send a response to the Sitemap because of a failure the better.

ServiceableReader: A Good Start

The ServiceableReader provides a good basis for building our database bo= und AttachmentReader.=C2=A0 The ServiceableReader implements the Recyclable, Lo= gEnabled and Serviceable interfaces and captures some of the information you will ne= ed for you.=C2=A0 We will need these three interfaces to get a reference to th= e DataSourceComponent, our Logger, and to clean up our request based artifact= s.=C2=A0 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.=C2=A0 For now, we are going to hard code the information.

The Skeleton

Our skeleton code will look like this:

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.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Map;

public class AttachmentReader extends ServiceableReader implements Cacheabl=
eProcessingComponent, Disposable
{
    private static final int BUFFER =3D 1024;
    public static String DB_RESOURCE_NAME =3D "ourdb"; // warning: static d=
atabase table name

    // ... skip many methods covered later

    public void setup( SourceResolver sourceResolver, Map model, String src=
, Parameters params )
       =C2=A0throws IOException, ProcessingException, SAXException
    {
        // ... skip setup code for now
    }

    public void generate() throws IOException, SAXException, ProcessingExce=
ption
    {
        // ... skip generate code for now
    }
}

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

    private DataSourceComponent datasource;
    private ServiceSelector dbselector;

Now we are going to override the service() method and implement= the dispose() method to get and cleanup after ourselves.

Collections =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D The document belongs to the following collections: documentation