Title: Problem writing a BetwixtTransformer

Hi,

I am trying to write a BetwixtTransformer based on CastorTransformer but have run into a problem.

Everything appears to be working Ok according to my logging messages until the XML is serialized when I get this error:

java.lang.RuntimeException: java.lang.NullPointerException
        at org.apache.xalan.transformer.TransformerImpl.run(TransformerImpl.java:3231)
        at java.lang.Thread.run(Thread.java:536)

To get the BetwixtTransformer up and running do the following:

1. Create an XML file to be read in via a generator:

<?xml version="1.0"?>
<document xmlns:betwixt="http://jakarta.apache.org/commons/betwixt/betwixttransfomer">
    <betwixt:InsertBean name="form" scope="request"/>
</document>

2. Add the following to your sitemap.xmap:

<map:components>

    <map:transformers   default="xslt">
        <map:transformer logger="sitemap.transformer.betwixt" name="betwixt" src="">

    </map:transformers>

    <map:actions>
        <map:action
            name    ="DisplayFormAction"
            src     ="test.DisplayFormAction"
            logger  ="sitemap.action"/>
    </map:actions>

</map:components>

<map:pipelines>

    <map:pipeline>

        <map:match pattern="form*.xml">
            <map:act type="DisplayFormAction">
                <map:parameter name="form-pk" value="{1}"/>
            </map:act>

            <map:generate src="">
            <map:transform type="betwixt"/>

            <map:transform type="log">
                <map:parameter name="logfile" value="c:/temp/logfile.log"/>
                <map:parameter name="append" value="no"/>
            </map:transform>

            <map:serialize type="xml"/>
        </map:match>


    </map:pipeline>

</map:pipelines>

3. Add the following two classes to your cocoon.war

/ ------------------ /
/ BetwixtTransformer /
/ ------------------ /


package org.apache.cocoon.transformation;

import org.apache.avalon.framework.parameters.Parameters;

import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.commons.betwixt.io.SAXBeanWriter;
import org.apache.commons.logging.impl.SimpleLog;

import org.xml.sax.Attributes;

import java.util.Map;

public class BetwixtTransformer extends AbstractTransformer
{
    private static final String BETWIXT_URI =
        "http://jakarta.apache.org/commons/betwixt/betwixttransfomer";
    private static final String CMD_INSERT_BEAN = "InsertBean";

    private static final String ATTRIB_NAME = "name";
    private static final String ATTRIB_SCOPE = "scope";
    private static final String VALUE_SITEMAP = "sitemap";
    private static final String VALUE_SESSION = "session";
    private static final String VALUE_REQUEST = "request";
    private static final String VALUE_CONTEXT = "context";

    private boolean in_betwixt_element = false;

    private Map objectModel;
    private SourceResolver resolver;

    /**
     * Default constructor
     */
    public BetwixtTransformer()
    {
    }

    /**
     * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(SourceResolver, Map, String, Parameters)
     */
    public void setup(
        SourceResolver resolver,
        Map objectModel,
        String source,
        Parameters params)
        throws
            org.apache.cocoon.ProcessingException,
            org.xml.sax.SAXException,
            java.io.IOException
    {
        this.objectModel = objectModel;
        this.resolver = resolver;
    }

    /**
     * @see org.xml.sax.ContentHandler#endElement(String, String, String)
     */
    public void endElement(String uri, String name, String raw)
        throws org.xml.sax.SAXException
    {
        getLogger().debug("endElement: " + name);

        // Check that we are currently in the Betwixt
        if (BETWIXT_URI.equals(uri))
        {
            in_betwixt_element = false;
            return;

        }

        super.endElement(uri, name, raw);
    }

    /**
     * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
     */
    public void startElement(
        String uri,
        String name,
        String raw,
        Attributes attr)
        throws org.xml.sax.SAXException
    {
        getLogger().debug("startElement: " + name);

        if (BETWIXT_URI.equals(uri))
        {
            in_betwixt_element = true;

            process(name, attr);
            return;
        }

        super.startElement(uri, name, raw, attr);
    }

    /**
     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
     */
    public void characters(char[] ch, int start, int len)
        throws org.xml.sax.SAXException
    {
        if (in_betwixt_element)
        {
            return;
        }

        super.characters(ch, start, len);
    }

    /**
     * Method process.
     * @param command
     * @param attr
     */
    private void process(String command, Attributes attr)
    {
        if (command.equals(CMD_INSERT_BEAN))
        {
            String sourcemap = attr.getValue(ATTRIB_SCOPE);
            String name = attr.getValue(ATTRIB_NAME);

            Object toInsert;

            Request request = ObjectModelHelper.getRequest(objectModel);

            if (name == null)
            {
                getLogger().error("attribut to insert not set");
            }
            /*
              searcl all maps for the given bean
            */
            else
            {
                if (sourcemap == null || VALUE_SITEMAP.equals(sourcemap))
                {
                    getLogger().debug(
                        "Searching bean '" + name + "' in " + VALUE_SITEMAP);

                    toInsert = objectModel.get(name);

                    if (toInsert != null)
                    {
                        insertBean(toInsert);

                        return;
                    }
                }

                if (sourcemap == null || VALUE_REQUEST.equals(sourcemap))
                {
                    getLogger().debug(
                        "Searching bean '" + name + "' in " + VALUE_REQUEST);

                    toInsert = request.getAttribute(name);

                    if (toInsert != null)
                    {
                        insertBean(toInsert);

                        return;
                    }
                }

                if (sourcemap == null || VALUE_SESSION.equals(sourcemap))
                {
                    getLogger().debug(
                        "Searching bean '" + name + "' in " + VALUE_SESSION);

                    Session session = request.getSession(false);

                    if (session != null)
                    {
                        toInsert = session.getAttribute(name);

                        if (toInsert != null)
                        {
                            insertBean(toInsert);

                            return;
                        }
                    }
                }

                if (sourcemap == null || VALUE_CONTEXT.equals(sourcemap))
                {
                    getLogger().debug(
                        "Searching bean '" + name + "' in " + VALUE_CONTEXT);

                    Context context = ObjectModelHelper.getContext(objectModel);

                    if (context != null)
                    {
                        toInsert = context.getAttribute(name);

                        if (toInsert != null)
                        {
                            insertBean(toInsert);

                            return;
                        }
                    }
                }
            }

            getLogger().debug("Bean " + name + " could not be found");

            return;
        } // end CMD_INSERT_BEAN

        getLogger().error("Unknown command: " + command);
    }

    /**
     * Method insertBean.
     * @param bean
     * @param mappingpath
     */
    //??    private void insertBean(Object bean, String mappingpath)
    private void insertBean(Object bean)
    {
        // If there is a bean then marshal it into XML
        if (bean != null)
        {
            getLogger().debug("Bean found");

            try
            {
                SAXBeanWriter writer =
                    new SAXBeanWriter(
                        new BetwixtSAXEventHandler(
                            contentHandler,
                            getLogger()));

                writer.setLog(new SimpleLog("Betwixt"));
                writer.getXMLIntrospector().setAttributesForPrimitives(false);
                writer.setWriteIDs(false);

                writer.write(bean);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        else
        {
            getLogger().debug("No bean found");
        }

    }
}

/ ---------------------- /
/ BetwixtSAXEventHandler /
/ ---------------------- /

package org.apache.cocoon.transformation;

import org.apache.avalon.framework.logger.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class BetwixtSAXEventHandler extends DefaultHandler
{
    private ContentHandler contentHandler;
    private Logger logger;

    /**
     * Constructor for BetwixtSAXEventHandler.
     */
    public BetwixtSAXEventHandler(ContentHandler contentHandler, Logger logger)
    {
        super();

        this.contentHandler = contentHandler;
        this.logger = logger;

        logger.debug("BetwixtSAXEventHandler initialised.");
    }

    /**
     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
     */
    public void characters(char[] chars, int offset, int length)
        throws SAXException
    {
        logger.debug("characters: " + new String(chars));

        contentHandler.characters(chars, offset, length);
    }

    /**
     * @see org.xml.sax.ContentHandler#endElement(String, String, String)
     */
    public void endElement(String namespaceURI, String localName, String qName)
        throws SAXException
    {
        logger.debug("endElement: " + localName + ":" + qName);

        contentHandler.endElement(namespaceURI, localName, qName);
    }

    /**
     * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
     */
    public void startElement(
        String namespaceURI,
        String localName,
        String qName,
        Attributes atts)
        throws SAXException
    {
        logger.debug("startElement: " + localName + ":" + qName);

        contentHandler.startElement(namespaceURI, localName, qName, atts);
    }
}

4. For Betwixt to work the following jar files will need to be added to the cocoon.war:

commons-betwixt-1.0-alpha-1.jar
commons-collections.jar
commons-digester.jar

5. Finally an Action needs to be written to stick a bean object in to the request.

Just in case you are asking 'why don't you just use the CastorTransformer?' the answer is that Castor was falling over with the bean I was using (the bean was a value object created using XDoclet). This happened inside and outside of Cocoon. A quick test using Betwixt standalone worked with any problem. Therefore I thought it might be useful to write a Betwixt transformer for cocoon.

Any help is much appreciated.

Keith.

********************************************************************************
  This electronic mail system is used for information purposes and is
  not intended to form any legal contract or binding agreement.
  The content is confidential and may be legally privileged. Access
  by anyone other than the addressee(s) is unauthorised and any
  disclosure, copying, distribution or any other action taken in
  reliance on it is prohibited and maybe unlawful

  All incoming and outgoing e-mail communications and attachments
  are scanned automatically by software designed to detect and remove
  any material containing viruses or other unauthorised content.  While
  we undertake best endeavours to ensure that this content checking
  software is up to date, recipients should take steps to assure themselves
  that e-mails received are secure.
********************************************************************************

Reply via email to