Table of Contents
List of Figures
List of Tables
List of Examples
The purpose of this document is to describe the architecture of web applications generated by Mod4j. Users of Mod4j need to understand this in order to be able to extend the generated application.
Atomicity, Consistency, Isolation, Durability
Create, Read, Update, Delete
Domain-Specific Language
Don't repeat yourself
Data Transfer Object
Enterprise JavaBean
Java Database Connectivity
Java Development Kit
Model-Driven Development
Object-Relational Mapping
Plain Old Java Object
Representational State Transfer
Remote Method Invocation
Service-Oriented Architecture
Simple Object Access Protocol
Structured Query Language
Chapter 2 describes the logical structure of an application generated by Mod4j , while chapter 3 describes its technical structure.
Table of Contents
This chapter describes the logical composition of the Mod4j Reference Architecture. It defines the layers, the component types in each layer and the responsibilities of these component types.
The Layers architectural pattern itself is described in [Busch96]. The Presentation Layer provides an interface to the system to a human user, presenting information and interpreting actions of the user. It uses the Service Layer to obtain the information or execute other operations that the Service Layer offers. The Service Layer provides access to the services of the Business Layer using a particular access protocol, like SOAP, EJB, RMI or local method invocation. The Business Layer provides services that implement functionality and business logic. The Data Layer provides access to persistent data on behalf of the Business Layer. The Domain Model consists of classes that model the part of the world that the application is about. The next paragraphs describes the responsibilities and the structure of the layers in more detail.
The Presentation Layer contains components that present information to a user and interprets his actions by executing functions of the system.Typical responsibilities of the Presentation Layer include:
Presenting data to the user. This implies mapping fields on a screen to attibutes of Data Transfer Objects received from the Service Layer, formatting of data, internationalisation en localisation of data.
Accepting data entered by the user. This implies applying simple validations on the data entered and keeping track of this data.
This Presentation Layer should not execute business functionality by itself, but instead delegate that responsibility to the Service Layer by calling its operations. Data is transferred to and from the Service Layer in the form of Data Transfer Objects.
TODO: expand this section when the User Interface DSL is nearer to completion.
The primary responsibility of the Service Layer is to isolate the business layer from the various protocols in use for remotely invoking its service operations. Examples of such protocols are SOAP or RESTful Web Services, messaging, EJB, RMI or plain old local mehod calls. A service layer presents the interface of the business layer in the form required for one particular access protocol. Therefore, a separate service layer is needed for each protocol by which the system will be accessed. This makes it clear that the presentation layer should not contain any business functionality, because that would have to be duplicated for each separate service layer. Code duplication is bad: it violates the DRY (Don't Repeat Yourself) principle.[1]
In addition, the service layer is reponsible for:
authentication and authorisation of the calling identities
exposing a collection of Data Transfer Objects to be used for transferring data between the service layer and its callers
translation of the information in the data transfer objects used for communication with the presentation layer to and from Domain Model objects used for communication with the business layer
making the call to each service operation an atomic (ACID) transaction.
The purpose of Data Transfer Objects (DTO's) is to decouple the core of the application from client applications, including the user interface, that communicate with it. A collection of DTO's form a common vocabulary between the communicating applications. In a SOA environment for instance, an application will commonly be required to communicate with other applications using a common canonical datamodel, that is defined outside of the control of the application we have to develop.
DTO's are very similar in structure to domain model classes. They have properties and can have references to other DTO's. They do not have validators and no constructors with mandatory fields. All properties are nullable.
For each DTO there is a correponding
Translator class. A Translator defines two
methods: toDto and fromDto. The
toDto method translates a domain model object into a DTO that is based on it. When a DTO has references to other DTO's that corresponds to references of the domain model class,
those object are also translated, recursively. The translators operate within a
transaction and therefore also on objects connected to the same Hibernate session. That
means that while traversing associated domain object to translate into their corresponding
DTO's, the translator may cause Hibernate
lazy loading to retrieve objects from the database
automatically.
The Business Layer is a facade for the Domain Model. It exposes the business functionality of the application in the form of methods, with arguments and return values from the domain model. These methods:
persist and retrieve domain objects by delegating to the Data Layer
delegate to domain model objects to execute reusable business functionality
implement business logic specific to a single business process
The responsibility of the Data Layer is to persist and retrieve data. The data is transferred between the data layer and its calling business layer in the form of arguments and return values based on the domain model. The persistence logic is dependent on the particular persistence technology in use, like a relational database, textfiles, XML documents or an XML database, or another application that exposes services for accessing data.
The data layer contains a number of data access objects, in principle one for each domain model class. Each such object:
Has CRUD-methods to create (C), retrieve (R), update (U) or delete (D) data contained in one domain model object
Can have methods to retrieve a list of objects based on a query
Must transform data from the domain model to the format in which they are persisted, and vice versa. This is done with Hibernate a Object-Relational Mapping (ORM) framework, like or Toplink.
Can offer paging facilities when a large result set may be retrieved.
May not maintain state.
The Domain Model contains classes that model the part of the world that the application is about. The domain model is developed in an object oriented way as advocated by [Fowler02] and [Evans03]. As much business functionality as possible is implemented as methods on domain model classes. Domain model objects:
Should expose methods that perform business actions or complex computations.
Should not be aware of persistence-related issues. Domain model objects should not have to worry about whether or not they are persisted, and how. For instance: they should not have create, retrieve, update or delete methods.
Trigger validation of business rules at any state change. Business rule violations are reported by raising an exception. When more than one business rule is violated by a state change, only one exception is raised that contains information about each one.
May leave the validation of certain types of business rule to lower layers, like the database. Good candidates for instance are unique rules, that are easily enforced by a relational database by defining unique constraints. The downside of this approach is that business rule violations in these cases are raised at a different moment than ordinary business, and that they have to be treated differently.
May trigger events to notify other interested objects of state changes.
Table of Contents
This chapter describes how the architectural layers described in the previous chapter are implemented. It describes how the code is divided into modules, how the Java classes are organised in packages, which frameworks are being used and in what way.
The application is implemented as a Maven project, consisting of a parent project of type pom, and a number of modules, one for each layer of the Logical View. The modules are contained in subdirectories of the directory of the parent project.
The names of the modules are formed by concatenating the Mod4j Project Name, a
dash ("-") and a keyword derived from the architectural layer the module implements. For a
hypothetical Mod4j project "RecordShop", the module names would be:
RecordShop-service, RecordShop-business,
RecordShop-data and RecordShop-domain.
The Maven project can be built by Maven from the command-line. Alternatively, the modules may be imported into Eclipse with the Q4E -plugin, and built from within Eclipse.
The Java classes are organised in Java packages. The package names are prefixed with a
root package name provided by the user at the time the Mod4j project was created by
the Mod4j Project Creation Wizard. After project creation the root package name is
stored in the file src/model/mod4j.properties as the value of the
property rootPackage. This file can be edited manually to change the root
package name. The packages names below this common prefix start with a package name
corresponding with the component name, that in turn is derived from the architectural layer
that it implements.
Table 3.1. Packages
| Name | Description |
|---|---|
| service | Interfaces and implementations of the service layer. |
| service.dto | Data Transfer Objects. |
| service.dto.translators | Java classes that translate Domain Objects to Data Transfer Objects, and vice versa. |
| business | Interfaces and implementations of the Domain Services in the business layer. |
| data | Interfaces that define the contracts of the Data Access Objects. |
| data.hibernate.spring | Spring/Hibernate specific implementations of the Data Access Object interfaces in the data package. |
| domain | Domain Objects: POJO classes that implement the Domain Model. |
| domain.businessrules | Java classes that implement Business Rules. |
The Spring framework is used as a general application framework. The objects making up
the application are being wired up by the Spring framework based on a number of XML
configuration files, generally one per layer. The Spring
ContextSingletonBeanFactoryLocator
class is used to create multiple hierarchical Spring IoC container instances, also
called bean factory or application context in Spring parlance, from these XML configuration
files. For the container of each layer, the container of the lower layer is the parent
container.

Beans defined in a direct or indirect parent context are visible in the child context,
but not vice versa. This hierarchical container is then used as the parent container of a
web application container. In this way, containers and the beans contained in them, may be
shared between several web applications, and loaded only once. Moreover, the hierarchical
composition of the container guarantees that dependencies between them are parallel to the
depencencies between the layers of the logical view. See section
3.9 Glue code and the evil singleton
in [Spring25] and the Javadoc for
ContextSingletonBeanFactoryLocator
for more details.
Hibernate is an object-relational mapping framework used to implement the data layer. This section document the choices made in several area' of this framework.
Hibernate offers a choice between mapping using JDK 5.0 annotations inside the domain model classes being mapped, and mapping using one or more separate XML mapping documents. We choose using XML mapping documents. The rationale is that we want to keep persistance concerns strictly separate from pure business logic. This way we can more easily change mapping strategies or even persistence frameworks.
Each persistent class is mapped in a separate XML document located in a directory
corresponding to the fully qualified Java package of the class being mapped, and with a
name constructed from the Java class name and a suffix ".hbm.xml". So, the fully qualified
path relative to the package root, for an XML mapping document for a persistent class
named org.company.recordshop.domain.Artist would be
org/company/recordshop/domain/Artist.hbm.xml.
Hibernate offers a choice between two strategies to access the fields of objects: property access, which is the default, and field access. We choose the second, field access. We prefer to keep programmatic access to the state of the object separate from framework access. For example, using a setter will trigger data validation, which is clearly not necessary when populating an object from persistent store. And it might trigger data transformations for derived fields.
Hibernate offers several strategies to implement concurrency control. We choose
optimistic concurrency control based on a version property, with a
negative unsaved-value. In the persisted class, this is a
private int field named version, initialized to
-1. The following example from a Hibernate mapping file illustrates this:
Example 3.1. Optimistic concurrency control mapping
<version name="version" unsaved-value="negative"/>
The corresponding field declaration in the mapped Java class looks like this:
Example 3.2. Optimistic concurrency control Java field
@SuppressWarnings("unused")
private int version = -1;
Since this field is only used by Hibernate, there are no access methods for
it.
The Java implementations of the data access objects are based on the Spring
HibernateDaoSupport
class and its
HibernateTemplate
helper class. This implies that all Hibernate, SQL and JDBC exceptions will be
converted to an appropriate subclass of
DataAccessException
class.
Java enum's are mapped with a specific implementation
<
of the Hibernate interface
rootPackage>.data.GenericEnumUserTypeorg.hibernate.usertype.UserType
. The following example illustrates this:
Example 3.3. Enumeration mapping
<property name="sexe">
<type name="org.company.recordshop.data.GenericEnumUserType">
<param name="enumClass">
org.company.recordshop.domain.SexeEnum
</param>
</type>
</property>
The enumClass must be a Java enum
class with a method id() and a method value(Integer
id). When an object with a enumeration property is persisted, the return
value of the id is stored in the database. When an object is
loaded from the database, the enumeration instance returned by the method
value(Integer id) with the persisted value as argument is set
as the value for the enumeration property.
Example 3.4. enum Java implementation
package org.company.recordshop.domain;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
* Sexe enumeration.
*/
public enum SexeEnum {
FEMALE(1), MALE(2);
private static final Map<Integer, SexeEnum> lookup =
new HashMap<Integer, SexeEnum>();
static {
for (SexeEnum s : EnumSet.allOf(SexeEnum.class))
lookup.put(s.id(), s);
}
private Integer id;
private SexeEnum(Integer id) {
this.id = id;
}
public Integer id() {
return id;
}
public static SexeEnum value(Integer id) {
return lookup.get(id);
}
}
The domain model classes need very little framework support. They are implemented as Plain Old Java Objects (POJO's). The business rule implementations do rely on some classes of the Spring framework, but they are implemented as separate classes. The domain model classes are not in any way dependent on them.
Domain model objects are designed to be at all times in a consistent state. To be in a consistent state means that all mandatory properties have a value, and that the object satisfies all business rules defined for the class. This principle is enforced by providing
a constructor with all mandatory properties as parameters
a set of classes that implement business rules, including rules to check for the presence of non-null values for mandatory properties.
The busines rules must be checked whenever the state of an object changes. For example, at the end of the constructor with the mandatory properties, and at the end of every setter.
Every domain model class needs at least two constructors. One of these is a no-argument constructor that is used by Hibernate. This constructor is not intented to be used for any other purpose, so it must be declared with the least visibility that still allows it to be used by Hibernate. This is protected visibility. This contructor must be present, but does not have to do anything. The other constructor takes all mandatory properties as parameters. The actual argument values for these parameters must be validated using the appropriate business rules.
All domain model classes must override the standard methods
equals and hashcode in a consistent
way. Two domain model class instances are considered equal either if they are the same
objects, or if they belong to the same class and have the same value
for their id property. The hashcode could return the hashcode of the
id property if it is non-null, and the hashcode of the superclass
if it is null.
Business rules are implemented as separate classes, one class per business rule. The
business rule implementation are based on two interfaces from the Spring framework:
Validator
and
Errors
as described in the paragraph 5.2 Validation using Spring's Validator interface of [Spring25]. A difference between our approach and the one from the Spring
manual is, that we provide a separate validator for each business rule instead of one per
domain class. Of course many types of validators can easily be parameterised and re-used
in different situations.
The business rules implementations must be invoked after every change of state to the object that could possibly violate the rule.