XSnapshot Quick Start

This is a short guide to quickly getting started with using XSnapshot. We quickly resnapshot the basic purpose and philosophy of xsnapshot, and then describe how to quickly start using it in a project. For more in depth discussion of the more advanced features refer to the User Guide (incomplete).

XSnapshot is a tool for generating snapshot classes based on javabean domain classes (which we call model classes). It allows you to specify which properties of the domain classes to include in snapshot classes, and to specify various transformations to apply to them. XSnapshot will then generate the snapshot classes, as well as helper classes that perform the conversions between snapshots and models. Finally XSnapshot includes a set of classes to help in configuring it at runtime and performing the conversions.

There are four basic steps to using xsnapshot:

  1. Mark up your data classes with xdoclet tags defining your snapshots.
  2. Add targets to your ant build file to generate the snapshots and helpers.
  3. Add code to configure the XSnapshot registry to know about your snapshots and helpers.
  4. Use the helpers in your business methods to convert between snapshots and models.

Mark up data classes

XSnapshot is a module for XDoclet, which lets you do code generation based on javadoc-like tags you add to your source classes. Thus the first step in using XSnapshot is adding the appropriate tags to your model classes that will drive the generation of the snapshot classes and helpers.

XSnapshot tags fall into two categories: class-level tags and property-level tags. Class-level tags are used to declare the snapshot classes defined for a model class. Property-level tags then specify properties to be included in each snapshot, and how the conversion should happen.

Please refer to the Tags Guide for detailed information on all the tags and attributes available for marking up your classes.

Add targets to ant build file

Now that you have added xsnapshot tags to your model classes, you need to add targets to your ant build script that will generate the snapshot and helper classes and the registry configuration file.

First, define a classpath that will be used by the xsnapshotdoclet task. this needs to include all the standard xdoclet jars, the xsnapshot jar, all of your model classes, as well as any jars containing any classes referenced from your model classes, if these classes are pertinent to the xsnapshot definitions (for example, if one of your model classes extends a class which comes from an external jar, that needs to be part of the classpath). for example:

<path id="xsnapshotdoclet.classpath">
    <fileset dir="${jar.repository.dir}" includes="${xsnapshot-module.jar}"/>
    <fileset dir="${xdoclet.home}/lib">
      <include name="*.jar"/>
    </fileset>
    <pathelement location="${j2ee.dir}/lib/j2ee.jar"/>
    <pathelement location="${ant.home}/lib/ant.jar"/>
  </path>

Next, add the target to generate the xsnapshots. Here is a sample target:

<target name="generate-xsnapshots" description="Builds xsnapshots files, if necessary" depends="-setup">
    <taskdef name="xsnapshotdoclet" classname="com.vecna.xsnapshot.ant.XSnapshotDocletTask" classpathref="xsnapshot.classpath"/>
                    <xsnapshotdoclet destdir="${build.generated-src.dir}" verbose="true" mergedir="${xdoclet.merge.dir}">
          <fileset dir="${src.dir}" includes="${persistent.package}/**/*.java"/>
          <packageSubstitution packages="${persistent.subpackage}" substituteWith="${snapshots.subpackage}"/>
          <snapshot/>
          <helper/>
        </xsnapshotdoclet>
        <xsnapshotdoclet destdir="${build.config.dir}" verbose="true" mergedir="${xdoclet.merge.dir}">
          <fileset dir="${src.dir}" includes="${persistent.package}/**/*.java"/>
          <packageSubstitution packages="${persistent.subpackage}" substituteWith="${snapshots.subpackage}"/>
          <properties/>
        </xsnapshotdoclet>

The first line defines the xsnapshot doclet task, using the classpath defined before. The xsnapshotdoclet task defines three subtasks, <snapshot/>, <helper/>, and <properties/> to generate the snapshots, helpers and the configuration file respectively. because you will generally want the output from the former two to go to a different place than the latter, you will need to run xsnapshotdoclet twice. Best practice is to have the <snapshot/> and <helper/> output classes to a generated-src directory somewhere under your build directory. The above example shows the two executions of <xsnapshotdoclet/>. Mergedir refers to the directory where xsnapshot will look for merge files.the <fileset/> element specifies the classes on which to run xsnapshot. the <packageSubstitution/> element allows you to define an automatic package replacement that should take place when xsnapshot encounters non fully qualified classnames. Normally, xsnapshot qualifies them, with the package of the class in which they are found; the package substitution modifies that.

Next, you should add the generated-src directory where xsnapshotdoclet generates the snapshots and helpers to the set of source files for your compile task, and add the runtime xsnapshot jar file to the classpath used for compiling. Also make sure that the generated configuration file is assembled into a place where it can be read at context initialization. see the section below on the latter.

Add code to configure the registry

The XSnapshotRegistry class is the runtime representation of xsnapshot configuration, such as which helpers are to be used for which snapshots. Thus, your web application needs to create and initialize an instance of XSnapshotRegistry, and then make it accessible to code that will be converting models to snapshots, and vice versa.

XSnapshot provides several options for performing the configuration.

  • The XSnapshotContextLoader class in com.vecna.xsnapshot.web. This is the simplest method. Simply register this class as a listener in web.xml, then add a init-param with the name xsnapshot.properties that points to the location of the confiration file. XSnapshotContextLoader will create and initialize an instance of XSnapshotRegistry and store a reference to it in XSnapshotRegistrySingleton. See the javadoc XSnapshotContextLoader for more detailes.
  • The XSnapshotPropertiesConfigurator class in com.vecna.xsnapshot.cfg. This class contains a static method to configure an existing instance of XSnapshotRegistry based on configuration contained in an instance of org.apache.commons.configuration.Configuration. XSnapshotContextLoader ultimately delegates to this.
  • Manual configuration. You can always call appropriate methods of the XSnapshotRegistry class to specify helpers for particular snapshots. Any previous associations are overridden. This is useful for specifying custom helpers that need special initalization.
  • Spring integration. If you are using Spring, the class XSnapshotRegistryFactoryBean in com.vecna.xsnapshot.spring makes it easy to configure and make available an instance of XSnapshotRegistry through a Spring application context. See the Spring Integration HOWTO for details.

Use the helpers in business methods

the final step in using XSnapshot is adding code to your business methods to convert between snapshots and models. XSnapshotUtils is the facade class that business methods should use to do this - they should NEVER refer to helper classes explicitly. XSnapshotUtils can be used in two ways - it has a set of static methods that take an instance of XSnapshotRegistry as an argument, and you can also create an instance of it passing it an XSnapshotRegistry and then use instance methods. If you wish to use the singleton pattern for the registry, there is also the XSnapshotSingletonUtils class which simply is a wrapper for XViewUtils that uses the registry held by XSnapshotRegistrySingleton. See the JavaDoc for XSnapshotUtils for detailed descriptions of the methods.

Note that the code in the helpers generated by xsnapshot for converting snapshots to models only copies over a very limited subset of the properties. To fully convert the snapshot to the model, you need to write additional code which properly copies over the rest of the properties. There are two ways to do this:

  • Write custom helpers that extend the auto-generated helper classes, override the copyIntoModel method, and copy over the rest of the properties. Then make sure to register these helpers with XSnapshotRegistry. This is easiest to do when integrating XSnapshot with Spring.
  • Write the code to copy the remaining properties from snapshot to model into your business classes. This is less ideal, but sometimes unavoidable if to do the conversion you need access to certain objects (such as the hibernate Session) that cannot be passed to the helpers.