Initialising

Initialisation is done inside the Tapestry Application Servlet; a class we sublcass and call inside the web.xml as a startup servlet. See the Tapestry setup guide for more info on this. Taking a peek inside this class we see:

   // Call our roll-your own resource loader to find the logging properties for Cayenne
   URL cayenneUrl = ResourceLoader.getResourceUrl("cayenne-log.properties");

   // Let Cayenne setup itself up with the logging properties
   Configuration.configureCommonLogging(cayenneUrl);

   // Bind a DataContext to the users session
   ServletUtil.initializeSharedConfiguration(config.getServletContext());

Cayenne has the concept of a Data Context. A Data Context is a place where a set of data is managed independantly of other Data contexts (though they can interact) by the Cayenne engine. Generally in a web application each user/session will have its own data context bound to it. Of course you may also have a global or application level data context etc.

Configuring

Under the crud-data/src/main/config folder are the Cayenne config files:

  • cayenne-log.properties; Based on log4j config, the first thing you'll want to do in a Dev environment is turn on SQL statement outputs
        log4j.logger.org.apache.cayenne.access.QueryLogger = DEBUG
    
  • cayenne.xml; The entry point to the a Cayenne application it defines high level configuration and what data maps and data nodes are to be used.
  • *.driver.xml; Defines what the data source locations are for the data being used. If you want to get this working with JNDI see the Tomcat setup guide.
  • *.map.xml; Defines the mapping of tables/fields into objects/variables.
  • ...and the code generate time Velocity template: superclass_with_generics.vm

    Unless you are a sucker for punishment don't go editing these files by hand, Cayenne is one of the frameowkrs out there that has provided a decent GUI editor for handling all the hard stuff.

Wiring the DataContext to the Tapestry Visit/Session

This is simple evough to acheive, the Cayenne folks have done the hard work. Simply add this to your web.xml:

  <listener>
     <listener-class>org.apache.cayenne.conf.WebApplicationContextProvider</listener-class>
  </listener>

Then to pull it off the session implement a function like this:

    /**
     * Gets the Cayenne datacontext off from the session bound one
     *
     * @return DataContext the cayennne dataContext
     * @see org.apache.cayenne.conf.WebApplicationContextProvider
     */
    public static DataContext getDataContext() throws UtilException {
        DataContext dc = null;
        try {
            // Get the data context that should be bound to ThreadLocal IF you've defined a
            // WebApplicationContextProvider
            dc = DataContext.getThreadDataContext();
        } catch (IllegalStateException e) {
            throw new UtilException(
                    "Could not get Thread DataContext.  If this keeps occuring there is a serious problem, such as excluding the following from your web apps web.xml file: " +
                            "    <listener>\n" +
                            "           <listener-class>org.apache.cayenne.conf.WebApplicationContextProvider</listener-class>\n" +
                            "    </listener>", e);
        }
        if (dc == null) {
            // Attention, this will not work in Web context if you
            // forgot to include the WebAppContextProvider, because
            // the DataContext is not bound to the http session!
            dc = DataContext.createDataContext();
            DataContext.bindThreadDataContext(dc);
            throw new UtilException("Could not get Thread DataContext so am now obtaining from Http Session, please ensure you have the following in your web.xml" +
                    "    <listener>\n" +
                    "           <listener-class>org.apache.cayenne.conf.WebApplicationContextProvider</listener-class>\n" +
                    "    </listener>");
        }
        return dc;
    }

Of course you can just put this in your page base class.