This section provides a logical view to OrderFlow's architecture.
OrderFlow is divided into logical layers, each having a particular responsibility. This approach isolates various system responsibilities from one another, therefore simplifying both system development and maintenance.
The following diagram shows the logical layers of the OrderFlow system, from the client layer down to the database layer. An explanation of the layers follows.
The Client Layer of OrderFlow renders the user interfaces that are presented to users in their own browsers. There are three main user interfaces:
- Desktop (also commonly called the web interface)
The Desktop interface is designed to be presented in a PC-based web browser, with standard and wide versions detected from the browser window size.
The Handheld interface is designed to be presented in a smaller browser on a rugged mobile computer, e.g.:
The Mobile interface is designed to be presented on a browser on a smart phone.
Interaction with the server is via HTTPS, using either GET or POST methods for page retrievals and form submissions respectively. In-page interaction is achieved using AJAX requests, which typically handle response data in the JSON format.
OrderFlow makes use of HTTPS sessions, to maintain user-specific data throughout the period in which a user accesses the application (without having to keep logging-in). It can also deposit cookies on the user's browser, to persist user preferences across different sessions. One example of this is to set the user's workstation.
OrderFlow's Interface Layer has primary responsibility for serving the client layer with the data to render the user view. This typically includes dynamic data that is associated with the user's session, and also dynamic data to do with what that the user has requested to view (e.g. details of a shipment).
The interface layer uses the Service Layer and the Data Access Layer to source this dynamic data.
OrderFlow follows the Model-View-Controller architectural pattern, supported by the Spring application framework. It contains many 'Controller' classes, annotated with Spring's Controller stereotype. Collaborators are auto-wired in using the Resource annotation, and methods serving accessible URLs are annotated with the RequestMapping web binding annotation. ('Collaborators' are other objects that a Controller class may need to source data from, or to perform other functions - such as objects in the service or data access layers.)
Each method that serves an accessible URL can declare common parameters, which the Spring framework automatically populates. Examples of such parameters are:
- Model (Map) - the context passed between the Client and Interface layers, containing all dynamic data. Both the client and the server can modify this context.
- HttpServletRequest - an object representing the HTTP request made by the client browser.
- HttpSession - an object to hold user-specific data across more than one HTTP request.
The mapped request methods would typically modify the model for interpretation by the client layer.
The code for the interface layer is typically found in modules with the following prefixes:
There may also be interface layer code in bespoke modules, which provide functionality specific to individual customers of Realtime Despatch.
The Service Layer of OrderFlow contains all the business logic and functionality that is not categorised as interface or data access functionality.
It is defined by the Java interfaces present in the rtd2-api module, some of which are described here:
- ApiRequestGenerator - generates requests to submit to remote APIs
- BatchManager - manages the creation, workflow and processing of shipment batches.
- CourierManager - provides all courier-specific functionality
- EventManager - provides functionality for submitting events in OrderFlow
- DataImporter - defines how data is imported into OrderFlow
- OrderStockAllocator - defines interface for allocating stock to order lines
- DespatchNoteGenerator - generates despatch notes for shipments
- PropertyManager - manages access to and update of application properties
- ReportManager - high-level interface for generating reports
- ScheduleManager - manages the scheduler and the invocation of scheduled jobs
- CrudService - provides basic create/read/update/delete service
- StateTransitionManager - manages state for transactional entities
- UserManager - manages all user logins and logouts
- InventoryManager - responsible for providing the inventory picture
- StockMoveTaskManager - provides methods for managing stock move tasks
The service layer also defines the domain objects in use within OrderFlow. These domain objects are mapped onto database tables by the data access layer. There are well over 200 such domain objects, so listing them here would be quite verbose. However, it is worth describing the categorisation of domain entities:
- Transactional entities such as shipments, deliveries, import batches and print items. These are business-relevant entities which are constantly being created during normal day-to-day operation of the system.
- Incidental entities such as schedule executions, user sessions and log entries. These are not business-relevant but are constantly being created.
- Reference data entities such as locations, products, properties and report configurations. These are relevant to a business but typically do not change as often as transactional entities.
These entity classes are all defined in the rtd.domain package within the rtd2-api module.
Data Access Layer
The Data Access Layer is the layer of code with responsibility to provide the higher logical layers with a mechanism to create, read, update and delete CRUD data in the data layer.
These responsibilities are shared across a single CrudService interface (defined in the rtd2-service package), and many Data Access Object (DAO) interfaces defined in the rtd.dao package.
Typically, each data access object interface is largely responsible for managing access for a single entity. The exception to this is the generic DAO interface, which acts on all entities.
The DAO interfaces are mainly concerned with reading the data in a convenient way for the other application layers to use. The CrudService and the generic DAO interface are mainly used for the creation, deletion and update operations.
The DAO interfaces are implemented either 'directly' via Java Database Connectivity, or through the Hibernate object/relational mapping framework. The JDBC implementations use SQL to query the data layer, whereas the Hibernate implementations use the Hibernate Query Language (HQL) to do this. The following diagram depicts this structure.
The Hibernate implementation can provide some automatic filtering when reading data objects from the data layer. This filtering ensures that only objects that the user has privilege to see are returned to the service or interface layer. This privilege is applicable at the organisation, channel and site levels, or any combination thereof.
Both implementations automatically restrict the number of data objects returned from the data layer. This is to maintain system performance by avoiding the potentially crippling effect of holding tens of thousands of objects in memory.
The Data Layer of OrderFlow consists of one or more relational databases. The number varies according to the configuration and size of the system, which is driven by the order volumes that the system is required to support.
The preferred relational database engine used by OrderFlow is MariaDB, an open-source, drop-in replacement for MySQL, which historically has been the most widely deployed open source database system. Although, MySQL is also still used in some OrderFlow deployments, MariaDB is now favoured mainly due to its superior performance in certain areas.
This list details the potential databases in use by OrderFlow (as mentioned in the overview section):
- Main database - this typically contains all of the data used by OrderFlow, including transactional and incidental entities, and reference data. For a simple, low-volume instance, this also includes file data. For a higher-volume instance, the file data will be stored in a separate Blob (Binary Large Object) database. OrderFlow can be configured to store files in the main database or the blob database.
- Blob database - this is used to store file data, e.g. generated reports, API message request and response contents, imported file contents etc. The benefit of using a separate database is that the main database is not impacted by having to store and retrieve relatively large data records, while trying to serve users and other clients.
- Archive database - OrderFlow can be configured to archive data from the main database into an archive database. This contains a subset of the tables in the main database, as not all data is eligible (i.e. useful) for archiving. If this database is not in use then OrderFlow will archive data from the main database to the file system, or it will simply delete it.
As one would expect from a relational database, the integrity of the data in the main database is maintained through many foreign key relationships. Indexes on relevant database table columns ensure that data retrieval remains performant.
The Script Layer of OrderFlow allows various logical aspects of the system to be defined by run-time Groovy scripts, rather than pre-compiled Java code. Such scripts can be used in application properties, or they can be applied to various configuration objects, such as import handlers or location selection definitions.
The benefit of this feature is that OrderFlow can be controlled in a very fine-grained manner Additionally, such control can be changed at run-time, without the need for a new version of the application to be built, and even without the need for the application to be re-started.
OrderFlow's Process Framework provides another mechanism to change the logical behaviour of the system without recourse to rebuild or restart it. It is more powerful than the script layer in that entire processes can be configured at run-time. These processes may query reports, use the results to submit API requests, update entities, invoke operations and so on.
The framework uses XML documents to define processes, ensuring that they are human-readable. Such XML documents can be tested (within OrderFlow) before being applied to live entities.
More details on this can be found in the Process Framework Guide.