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 byMod4j , 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 Objects that model the part of the world of interest to the application. 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 fromDto method translates the DTO into an instance of its corresponding domain model class. If the
DTO has references however, these are
not translated. There is a specific reason for this asymmetric
behaviour that has to do with passing DTO's
corresponding to existing domain objects as an arguments to services. In general, the
client can manipulate objects referenced by a DTO at
will, adding, deleting or updating instances. Faithfully merging these intended changes
with an existing object retrieved from persistent storage would require the translator to
interpret the changes by comparing them to the state of the corresponding domain object,
including the referenced associated objects. This is at the moment considered too great a
challenge. A client of the application will have to send a DTO and its associated objects by sending the DTO itself, and each of the deleted, changed of added associated objects by
calling separate specialised services that reflect the intended behaviour.
The Business Layer is a facade for the Domain Model. It exposed 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 objects that model the part of the world that is of interest to the application. The domain model is preferably 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 should be 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 all prefixed with a root package name
provided by the user at the time the Mod4j project was created by the Mod4j
Project Creation Wizard, and stored in the file
src/model/mod4j.properties as the value of the property
rootPackage. 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 also 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.
The optimistic locking strategy is 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. Since this field is only used by Hibernate, there should be no methods to change
it.
The Java implementations of the data access objects are based on the Spring
HibernateDaoSupport
and its
HibernateTemplate
helper. This implies that all Hibernate, SQL
and JDBC exceptions will be converted to an
appropriate subclass of
DataAccessException
.
Java enum's are mapped with a specific implementation
org.company.recordshop.data.GenericEnumUserType of the Hibernate
interface
org.hibernate.usertype.UserType
. The following example illustrates this:
Example 3.1. 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.
All domain model classes must override the standard methods
equals and hashcode in a consistent way.
Two domain model class instances are considered equal if they are the same, 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.