Print
Overview

Overview Of Trails

Introduction

Trails is a full-stack web application framework.

A full-stack (web application) framework's primary goals are to provide a single set of components, covering the entire spectrum of things you'll need to build web applications, and to ensure that those components work well with one another.

Trails Stack:

Trails allows rapid CRUD application development by automatically creating list and edit pages for POJOs. Trails uses introspection to gather information about bean properties and creates representations and editors depending on their type, for example.

Trails itself consists of three main components: a persistence service, a descriptor service that provides meta data for the domain beans and an editor service that provides appropriate editor components based on meta data. For most work, Trails depends on several other frameworks. To understand Trails, it is necessary to understand a bit about the frameworks it uses.

Overview of Trails modules

Since Trails 1.1 we've broken the monolithic jar into four different modules. With modularization we've made it possible to separate the presenation and persistence logic and make it easy to introduce new persistence strategies (ie. db4o, jpa) in the future. Additionally, we've separate the test and security related features into their own modules.

Trails currently consists of four modules:

  • trails-core: As the name says it includes the core logic, depending on Tapestry and Spring but not Hibernate. You can provide your own PersistenceService and use this module to leverage all the Trails magic with its form rendering capabilities.
  • trails-hibernate: Includes the persistence logic and provides a decorator that understands Hibernate metadata and gives Trails more metadata to work with. It also provides 3 Hibernate specific editors that are extensions of editors in trails-core.
  • trails-test: base classes and configurations to test Trails internal. If you don't develop Trails components you probably won't need this.
  • trails-security: based on Hibernate and Acegi Security for Spring. It provides basic security capabilities. Security as separate module makes it possible to reduce the needed dependencies and improve response time in projects that don't need security. In Trails 1.0 internal security checking is always there even if you don'tt need it.

Spring

Spring is a dependency injection (sometimes known as inversion of control) framework, designed to make configuring and connecting numerous java objects easier. The Spring website explains the benefits and principles of the Spring Framework in great detail, but for a really, really short idea of the Spring advantage, consider the following comparison:

Old'n'Busted: singletons, getInstance() methods, lots of static methods, objects that set references to other objects.

Why is this bad? Because its difficult to configure or swap objects (this means changing references in multiple places). It's difficult to test, it's difficult to understand the object graph that exists when the application is running.

New & Hip: Define objects as POJOs. A Spring configuration configures the objects and sets references from one object to another. When the application starts, Spring instantiates all objects and sets all references. The objects themselves never have to worry about this.

Why is this good? Because it's easy to configure; it's easy to swap out objects for different objects (e.g. mock objects for testing); it's easy to test; Spring has lots of fancy extras (AOP for example).

How Trails uses Spring

The Spring configuration of a typical Trails application, stored in WEB-INF/applicationContext.xml, defines a number of important objects:

  • sessionFactory - a Hibernate session factory
  • transactionManager - a hibernate transaction manager
  • persistenceService - a Trails object that provides the connection

    between Trails and Hibernate
  • descriptorService - a Trails object that gathers meta information

    for the domain model. This contains a list of all hibernate-persisted

    types and decorators that add or modify meta information.
  • editorService - a Trails object that provides an appropriate editor

    for a property, based on its meta information. The editorService

    configuration specifies editors for strings, numbers, identifiers, dates

    and collections, for example.

Hibernate

Hibernate is a powerful ORM / persistence framework. It is especially useful in applications that are centered around a java domain model. For complicated databases with lots of stored procedures, Hibernate may not necessarily be the best option. But for Trails it's perfect.

  • It persists POJOs: the POJOs themselves do not contain any 'obtrusive'

    code specific to persistence.
  • A mapping of POJOs to database tables is done with annotations or

    separate xml configuration, depending on your preference.
  • Hibernate can optionally create the database tables for you based

    on your mapping, if the tables do not exist yet.
  • It features lazy loading of collections, so retrieving one object

    from persistent storage does not pull a complete object graph from

    storage.

Using Hibernate with Trails is pretty straightforward. For simple applications, you hardly need to do anything other than specifying which database you want to use. For more complex cases, you typically use Hibernate annotations.

Tapestry

Tapestry is a powerful web framework; Trails is basically a Tapestry application.

Tapestry is component based, like JSF, WebObjects and Wicket, as opposed to being page oriented, like !SpringMVC, Struts, and numerous other web frameworks.

Old'n'busted page oriented frameworks: servlets or pages handle (http-)requests, parse parameters and generate a (http-)response. The flow, and programming model, is basically (crudely said): user clicks url, servlet handles url, servlet generates resulting http.

New & hip component based: pages are components that contain other components, like links, tables, forms, etcetera. Components consist of a presentation (a HTML fragment, usually) and behaviour. A submit button could have its own onSubmit() method, for example. Components, including their behaviour, can be easily reused across pages.

How Trails uses Tapestry

Without a component based framework, Trails would be (nearly?) impossible. The editors that Trails' editorService provides are Tapestry components, for example, that contain behaviour specific to the component (i.e. a way to synchronize the editor presentation with POJO property values). The editor components are automatically placed where they are needed, providing flexibility that would be difficult to create with page oriented frameworks.

A Trails Tapestry component

Tapestry components consist of three parts:

  • a HTML fragment for the component's presentation. HTML

    fragments typically contain references to other Tapestry

    components (text fields, ForEach components, submit buttons,

    links to other pages, etcetera).
  • a component specification, defining and configuring components

    that are used in the HTML fragment and the Java class that provides

    the behaviour for the component
  • a Java class that contains the component's behaviour and an interface

    for the HTML presentation.

For example, a component's HTML fragment could contain a ForEach component that iterates over a collection provided by a getItemList() method in the java part.

OGNL

Tapestry uses OGNL (Object Graph Navigation Language) to interact with Java objects from within Tapestry HTML code. OGNL is similar to, but more powerful than, JSP's Expression Language (EL).

How Trails uses OGNL

Tapestry components rely heavily on OGNL for component configuration and interaction between HTML and java parts of a component. But Trails itself also uses OGNL, in the editorService for example. The spring configuration for the editorService defines a map, mapping OGNL expressions to editors. For every property on an Edit page, Trails iterates over the editor map, evaluating its keys (OGNL expressions). The first editor is picked whose key evaluates to true. For example, the numberEditor editor is used when the IPropertyDescriptor's =isNumeric() method returns true and the isIdentifier() method returns false:

<verbatim>

<entry>

<key><value>numeric and !identifier</value></key>

<bean class="org.apache.tapestry.util.ComponentAddress">

<constructor-arg index="0"><value>trails:Editors</value></constructor-arg>

<constructor-arg index="1"><value>numberEditor</value></constructor-arg>

</bean>

</entry>

</verbatim>

A Trails application

A Trails application is basically a Tapestry application with a lot of clever stuff. A Home page for a Trails app consists of a list of ListAllLink components; one for every type defined in the descriptorService. By default, this means every hibernate-persisted type.

List and Edit pages

A ListAllLink provides a link to a bean's List page. The List page shows a table containing all instances of a particular bean, as well as links to add or search instances. A DefaultList page is used unless you specify a custom list page, which should be called _beanname_List. It is possible to create custom markup for the page, for example, or define the properties that should be shown in the table.

By default, ListAllLink displays a bean's identifier as a link. Click the link, and Trails presents an automatically generated DefaultEdit page. This page contains editors for every property, as well as an option to remove the instance. When the DefaultEdit page does not suffice, it is possible to create a custom edit page, _beanname_Edit.

Trails editors

Trails provides a number of editors by default (configured in the editorService bean in the Spring configuration), such as:

  • identifier - component that displays a bean's id in an appropriate

    way, depending on the id being numeric or not,

    editable or read only, etcetera.
  • string editor - displays a TextField component

    (a html input tag with type"text"= attribute) for "small" strings
  • string editor for large strings - a !TextArea component where multi-line

    text can be entered. This editor is used if the PropertyDescriptor's

    isLarge() method returns true, which is the case for String

    properties that map to large varchar fields in the database.
  • collection editors - an editor for Collection properties.

Possible custom editors could be:

  • HTML editor for String properties (FCKEditor is provided by Trails)
  • Flag editors that allow (multiple?) selection of flags that map to a

    single numerical field

See Adding Custom Editor for a short howto on adding custom editors to Trails.




  1. full-stack framework in a nutshell by James Bennett



Powered by Atlassian Confluence