Cms module
This module adds the content-management system (CMS) capabilities to your project. Adding it to your classpath will let you create a website and later manage the content inside it, without restarting or redeploying your project.
Structural elements
Before diving in the CMS module, you need to grasp the difference between the different notions. This module talks about PageTemplate
, Page
, CmsSlot
and Widget
. Please read below about each one of them.
Page templates
Your website is composed of different web-pages. Each of these pages can be further classified, based on the design fuctionalities they offer. The PageTemplate
is exactly this - the template your page is of, and the categorization of this page. We use the page templates to keep the consistency across the whole website. For example, you might have a single-column
page template, and a two-column
page template.
These page templates very roughly describe what type of pages you will have in your project. Every PageTemplate
has a frontendTemplateName
property of type java.lang.String
which points to the location of a JSP file, which we will use to render the pages that have this page template:
Unresolved directive in <stdin> - include::/opt/bitnami/apps/jenkins/jenkins_home/workspace/nemesis-platform-master/modules/nemesis-module-cms/src/main/java/com/nemesis/platform/module/cms/core/definition/CmsPageTemplateEntityDefinition.java[tags=frontendTemplateName]
The page templates have a style
property that stores some custom CSS style so that you don’t need to redeploy the site every time there is a tiny change in the CSS.
Your pages do also have a style property. If defined, the custom page CSS overrides the template’s CSS.
|
Content slots
Once you have defined how many different templates you will have in your system and how many pages you will have, it is time to put some content in those pages. This is done by means of using the CmsSlot
objects. Content slots are defined in two parts - first they are created in the database (just like pages), but they are also defined in the view layer which specifies where in the DOM they will sit.
Further, on every PageTemplate
there is a java.util.Collection
of CmsSlot
objects assigned to it.
Unresolved directive in <stdin> - include::/opt/bitnami/apps/jenkins/jenkins_home/workspace/nemesis-platform-master/modules/nemesis-module-cms/src/main/java/com/nemesis/platform/module/cms/core/definition/CmsPageTemplateEntityDefinition.java[tags=slots]
This allows us to define what areas of the look and feel will be editable later on, when we run the website. Continuing our example our single-column
template can define the following slots: cs-logo
and cs-footer
and the two-column
page template would define the same.
It might seem useless to define two page templates, while they have the same content slots defined. You must remember that each page template has a different view URL assigned to it. In this way we can have different structure of the DOM for different page templates (single column, two-column, etc.) |
Finally, every Page
object also holds a java.util.Collection
of CmsSlot
objects.
This allows the page to define some more content slots that are different per page, while the page template will define the slots that are common for every page that is of this page template. In our scenario, the homepage
will define content slots cs-section1
, cs-section2
and cs-section3
, while the loginpage
will have cs-left-box
and cs-right-box
.
Widgets
Widgets are the functionalities that you can change on the page. You can change a certain slot to contain a banner, or an image, or a piece of text, or a carousel of some sort, or pretty much anything. As you can see, the CmsSlot
has a relation to a java.util.Collection
of widgets:
Unresolved directive in <stdin> - include::/opt/bitnami/apps/jenkins/jenkins_home/workspace/nemesis-platform-master/modules/nemesis-module-cms/src/main/java/com/nemesis/platform/module/cms/core/definition/CmsSlotEntityDefinition.java[tags=widgets]
This allows you to specify which widgets will be rendered in which slots. If more than one widget is added in a slot, they will be rendered one after another. Each widget extends the AbstractActivatableEntityDefinition
which adds a field called active
to control which widgets are active and which not. Widgets also extend the AbstractFilterableEntityDefinition
to specify a java.util.Collection
of AbstractFilterEntityDefinition
to again control which widgets will be visible when.
Request flow
Here’s how a sample request flow goes, from the moment a user types a page url to the moment the page is rendered on his screen.
-
First, the user types a URL (let’s imagine this is
/contacts
) and their browser makes a request to the server. -
Then the platform tries to find a Spring MVC controller to handle this request. If a controller is found, the request is handled and the controller must return the name of the view the server will render to the client.
-
If a controller is not found, then the platform will try to find a
Page
instance in the database withurlPath
field matching what was requested (/contacts
). If a page is not found, then the platform will try to find aPage
in the database with theid
field matching what was requested. If no page is found, the platform will throw aRequestedResourcesNotFoundException
and the controller will return a 404 page to be rendered. -
If, in the previous step, a page is found, the controller will add the content slots of the page, together with the content slots of the template in the request model and return the view URL from the
masterTemplate
of the page template of the page that was found. -
When rendering the view, the tag libraries will make so that the content slots defined in the view, will renderer the widgets that are currently active in the given content slot.
-
The end result is an HTML document that gets sent back to the client.
Development
Core
Entity Definitions
The definitions in this module have id discriminators in the range 150-170. |
The PageKeywordDestinationEntityDefinition is a type of SearchKeywordDestinationEntityDefinition:

The entity denotes e redirection to a given page, passed as a method parameter. The defined property here is page
. It comes along with the respective getter and setter.
The AbstractCmsEntityDefinition extends the AbstractEntityDefinition:

Via the respective getter-setter pairs, the following information can be retrieved/stored in the database:
Property | Description |
---|---|
title |
stores the title of the cms entity |
content |
stores the content of the cms entity |
publishDate |
stores the date this entity is to be published |
The AbstractMetaDatableEntityDefinition extends the functionalities defined within the AbstractEntityDefinition. The AbstractMetaDatableEntityDefinition
is a base class for all entities that need to provide metadata attributes.

The one getter-setter pair defines a map of <String, String> metadata attributes.
The CmsPageTemplateEntityDefinition extends the functionalities defined within the AbstractEntityDefinition and the AbstractCatalogableEntityDefinition:

This is the base definition for all abstract templates. Via the respective getter-setter pairs, the following information can be retrieved/stored in the database:
Property | Description |
---|---|
name |
stores the descriptive name of the template |
frontendTemplateName |
stores the template’s name, used as part of the url to access it from the frontend |
style |
stores the custom css styles to be applied on every page of the template |
cssClasses |
stores the applicable for the template css classes |
cmsSlots |
stores a set of |
The CmsCatalogEntityDefinition adds the cms-related attributes to the CatalogEntityDefinition. The CatalogEntityDefinition
, in its turn, extends the AbstractEntityDefinition and the AbstractNameableEntityDefinition.

The getter-setter within the sites
property lets you retrieve/store a set of sites the catalog belongs to.
The CmsPageEntityDefinition is the base definition for all abstract pages. It extends the AbstractEntityDefinition, the AbstractActivatableEntityDefinition, the AbstractCatalogableEntityDefinition, the AbstractMetaDatableEntityDefinition and the AbstractCategorizableEntityDefinition, the AbstractFilterableEntityDefinition and the AbstractSearchEngineOptimizableEntityDefinition:

This is the basic entity for all content pages. The defined here getter-setter pair is homePage. It stores information if the current page is the home page or not
The url of the page is constructed from the categories the page belongs to + the code of the page (i.e. '/A/B/C/page.code'). |
Property | Description |
---|---|
title |
stores the title of the page |
name |
stores the descriptive name of the page |
cssClasses |
stores the applicable for page the css classes |
style |
stores the custom css styles to be applied on every page of the template |
masterTemplate |
stores the master template for the page, defining the view url of a given page |
slots |
stores a set of |
The CmsSiteEntityDefinition adds the cms-related attributes to the SiteEntityDefinition and the AbstractMetaDatableEntityDefinition :

This is the basic entity for the cms site. Via the respective getter-setter pairs, the following information can be retrieved/stored in the database:
Property | Description |
---|---|
googleAnalyticsKey |
stores the Google analytics key for the site |
responsive |
stores information if the site is responsive or not |
viewSuffix |
stores the view suffix for the site ( |
cmsCatalogs |
stores a set of |
startingPage |
stores the starting page for the site |
listerPage |
stores the lister page for this site |
detailsPage |
stores the details page for this site |
theme |
stores the theme for the site |
robots |
stores the |
The CmsSlotEntityDefinition extends the AbstractEntityDefinition the AbstractActivatableEntityDefinition and the AbstractCatalogableEntityDefinition. Keep in mind that content slots are defined on every page or template and contain a number of widgets to be displayed on the page:

Via the respective getter-setter pairs, the following information can be retrieved/stored in the database:
Property | Description |
---|---|
position |
stores the position of the content slot |
cssClasses |
stores the css classes for content slot |
page |
stores the page template the content slot belongs to |
widgets |
stores a list of |
The PageEmailMessageEntityDefinition extends the features of the EmailMessageEntityDefinition:

The page
property, defined here, lets you keep track of the particular page the email message is for.
The SiteThemeEntityDefinition extends the AbstractEntityDefinition and the AbstractPicturableEntityDefinition:

The description
getter-setter pairs lets you retrieve/store the description for the theme in the database.
The WidgetEntityDefinition is the basic definition for all widgets. It extends the features, defined in AbstractEntityDefinition, AbstractActivatableEntityDefinition, AbstractCatalogableEntityDefinition, AbstractCmsEntityDefinition and AbstractFilterableEntityDefinition:

The widgtes are contained within the content slots of a particular page. Via the respective getter-setter pairs, the following information can be retrieved/stored in the database:
Property | Description |
---|---|
name |
stores the name of the widget |
cssClasses |
stores the css classes for the widget |
initializeScript |
stores the init JS script for the widget |
Spring Data JPA Repositories
The PageKeywordDestinationRepository extends the BaseEntityRepository and is the corresponding Spring Data JPA repository for the PageKeywordDestinationEntityDefinition
.

The CmsCatalogRepository extends the BaseEntityRepository and is the corresponding Spring Data JPA repository for the CmsCatalogEntityDefinition
.

The CmsPageRepository extends the ActivatableRepository and is the corresponding Spring Data JPA repository for the CmsPageEntityDefinition
.

The CmsSlotRepository extends the ActivatableRepository and the BaseCatalogableEntityRepository. The CmsSlotRepository
is the corresponding Spring Data JPA repository for the CmsSlotEntityDefinition
.

The PageEmailMessageRepository extends the BaseEntityRepository and is the corresponding Spring Data JPA repository for the PageEmailMessageEntityDefinition
.

The PageTemplateRepository extends the BaseCatalogableEntityRepository and is the corresponding Spring Data JPA repository for the PageTemplateEntityDefinition
.

The SiteThemeRepository extends the BaseEntityRepository and is the corresponding Spring Data JPA repository for the SiteThemeRepository
.

The WidgetRepository extends the ActivatableRepository and the BaseCatalogableEntityRepository. The WidgetRepository
is the corresponding Spring Data JPA repository for the WidgetEntityDefinition
.

Business Services
Among the helper functionalities, defined within the AbstractPageService, are:
Description | Method |
---|---|
to obtain the name of the current frontend template* |
getFrontendTemplateName() |
to obtain the home page for the entity |
getHomepage() |
to obtain a collection of page entities by the given urlPath or code |
getPagesForUrlPathOrCode() |
to obtain the home page urlPath |
getUrlPathOrId() |
to obtain all content slots for the given page |
getCmsSlotsForPage() |
The CmsSiteService adds the cms features to the SiteService. As you may see from the diagram below, the inheritance goes further to the SiteEntityDefinition and, respectively, the AbstractEntityDefinition, and the AbstractDescriptionableEntityDefinition.

The helper functionality, defined here, is getStartPageUrlPathOrId()
. It allows you to obtain the urlPath or the id of the starting page for the given site.
The CmsSlotService is to hold the service logic for the cms module related to CmsSlotEntityDefinition
The PageTemplateService is to hold the service logic for each of the page templates.
The WidgetService is to hold the service logic for the cms widgets.
Facade
MapperFactoryConfigurers
The CmsPageMapperFactoryConfigurer implements the MapperFactoryConfigurer, converting the CmsPageEntityDefinition
to PageDtoDefinition
:

The registered conversions, within the configurer, are:
-
from
CmsSlotEntityDefinition
toCmsSlot
, -
from
PageTemplateEntityDefinition
toPageTemplateDto
, -
from
CmsPageEntityDefinition
toPageDtoDefinition
.
The CmsSiteMapperFactoryConfigurer implements the MapperFactoryConfigurer:

There are 2 conversions, registered here:
-
from
SiteThemeEntityDefinition
toSiteThemeDto
and -
from
CmsSiteEntityDefinition
toCmsSiteDtoDefinition
The conversion is done via the byDefault()
.
The WidgetMapperFactoryConfigurer implements the MapperFactoryConfigurer:

The two conversions, registered byDefault()
here, are:
-
from
WidgetEntityDefinition
toWidgetDtoDefinition
and -
from
WidgetEntityDefinition
toSearchRequestCmsDtoDefinition
More about the mapping configurations you may read in the respective Orika guide.
Dto definitions
The AbstractMetaDatableDtoDefinition is the corresponding Dto object for the AbstractMetaDatableEntityDefinition
.
The CmsDtoDefinition extends the SearchableDtoDefinition.

The CmsSiteDtoDefinition extends the SiteDtoDefinition and the AbstractMetaDatableDtoDefinition. This is the corresponding Dto object for the CmsSiteEntityDefinition
.

The CmsSlotDto is the corresponding Dto object for the CmsSlotEntityDefinition
The PageDtoDefinition is the corresponding Dto object for the CmsPageEntityDefinition
. The PageDtoDefinition
extends the AbstractMetaDatableDtoDefinition and the AbstractSearchEngineOptimizableDtoDefinition:

The PageTemplateDto is the corresponding Dto object for the PageTemplateEntityDefinition
The WidgetDtoDefinition extends the AbstractEntityDtoDefinition. This is the corresponding Dto object for the WidgetEntityDefinition
.

Facades
Some helper methods are defined within the AbstractPageFacade. Among the functionalities included here, are:
-
to obtain a page Dto for the given pathUrl or code,
-
to obtain the current home page,
-
to obtain the urlPath or the id for the given page Dto,
-
to obtain the name of the current frontend template,
-
to obtain the category, as well as the product Dto pages,
-
to obtain the CMS slots, available on the page
The CmsSiteFacade extends the SiteFacade:

An extra functionality, defined here, is the option to obtain either the urlPath, or id of the starting page of the given site.
Some helper methods are defined within the CmsSlotFacade. Among the functionalities included here, are:
-
to obtain a CMS slot with the given code,
-
to obtain the page of the particular content slot,
-
to obtain either all, or a random widget for the given slot
The PageTemplateFacade adds the option to get all cms slots for the template with the given template code.
Some helper methods are defined within the WidgetFacade. Among the functionalities included here, are:
-
to load or obtain a widget with given id, as well as
-
to check if a particular widget is visible or not
Storefront
As the base controller, the AbstractController provides all of the common functionalities for the controllers.
The root for requests is /
.
The AbstractViewController is the base controller for all page controllers. Here are defined all of the common functionalities for them.
The root of the views is at /layout/
The AbstractWidgetController is the base controller for all widgets. As such, it defines all of their common functionalities.
The ContentViewController is aimed at rendering views directly. It comes in handy when you need to fetch the content of the view.
The HTTP Endpoint is at /content/view/{path}
The DefaultWidgetController extends the AbstractWidgetController.

The HTTP Endpoint is at /view/
.
The FallbackCmsViewController extends the AbstractViewController and implements the Spring mvc Controller:

Each client’s search request for a particular page is based on the page’s urlPath
parameter. The urlPath is checked against the stored information in the database. When a resource is mapped to the request, the particular view is rendered. Otherwise, the FallbackCmsViewController
returns a 404 resource not found
message.
The RobotsController defines an HTTP Endpoint at /robots.txt
. The respective GET method handles the web robots instructions.
The generated views may be found at WEB-INF/views/${DEVICE_PREFIX}]/cms/widget.[EXTENSION]
For further details on mapping, check the corresponding mapping actuator accessible at /platform/mappings
.
Configuration
Name | Type | Description |
---|---|---|
nemesis.cms.include-site-in-view-name |
java.lang.Boolean |
|
nemesis.cms.maintenance-during-migration |
java.lang.Boolean |
|
nemesis.cms.path-locale-filter-exclude-urls |
java.util.List<java.lang.String> |
Unmap the following urls from path-locale filter. |
nemesis.cms.view-root |
java.lang.String |
|
nemesis.cms.widget.base-path |
java.lang.String |
Controller base-path - all widget controllers will be mapped under this url. |