Skip to main content

Content service

The content service is a component that implements a generic key-value storage for various metadata used by the ActiveViam products (e.g. calculated measures and KPIs for Atoti Server, bookmarks and application settings for Atoti UI).

See the how-to guide for examples of configuration.

Architecture

The content service provides a way for components of Atoti to remotely store data in a way similar to a file system. Data is organized into directories that can contain files or other directories. Each file or directory has associated permissions that grant read or write access to given roles.

The content service is represented by the interface IContentService which provides basic operations to access and store data. There also exists an ActivePivot Content Service (interface IActivePivotContentService) which is a convenience wrapper around the generic content service contract, with methods specialized for dealing with ActivePivot metadata.

A typical setup is shown below. One machine contains a content service that is accessible with a REST API and actually stores and retrieves data (right), and the other machine contains Atoti Server along with a content service that simply delegates requests to the remote content service (left).

Content server architecture

By default, Atoti Server will start an embedded content service directly in the same JVM, thus not requiring a second machine.

Configuration

Types of content services

A content service can be of one of the following types:

  • An in-memory content service does not persist its content: all data will be lost when the server is stopped.
  • A Hibernate content service relies on Hibernate to store and persist its content in a database.
  • A remote content service relies on a remote REST-enabled content service to store its data, and delegates all of its calls to the content service that is hosted there.
    As such its behavior depends on which type of content service has been set up on the remote machine.

Database configuration for Hibernate content service

As for any Hibernate application, it is possible to manage the SQL database manually and connect the Hibernate service to an already prepared database. The easiest and most robust way to get the exact SQL commands to create an appropriate database manually is yet again to use Hibernate features, because of varying SQL dialects. For example, one may define

atoti.server.content-service.hibernate.hibernate-options.hibernate.hbm2ddl.auto: create
atoti.server.content-service.hibernate.hibernate-options.hibernate.show_sql: true

and Hibernate will show the exact SQL commands written in an appropriate SQL dialect. Then these commands may be extended and modified by the user without any further Java code interactions.

There are a few facts that may be useful during database configuration:

  • The optimal initial size of the required storage is very dependent on your use case, but we saw very few clients requiring more than 1GB of memory in total.
  • The growth of the database will be directly related to the number of users (settings that need to be saved) and the number of dashboards/folders.
  • The typical workload is a lot of reads and only a few writes (i.e. when users need to save something).
  • Each user action has a direct impact on the underlying database. If the user removes bookmarks or filters, the data will be automatically cleared from the database.
  • In Atoti Server we do not use any of the Spring Data JPA features.
  • Content services use locks with JVM scope by default. In some cases such as when using replication, multiple content services may be backed by the same database. To avoid concurrency issues in these cases, it is possible to instead use database-level locks. This can be achieved using the databaseLocks method as shown in the how-to guide.

Sharing one content service between multiple Atoti instances

There are different use cases possible here, for instance:

  • When using a distributed architecture to deploy Atoti.
  • When deploying multiple projects (one customized Atoti application for each) but wanting a single Atoti UI to browse all relevant bookmarks from one place. There are two sub-cases to consider here:
    • Multiple of Atoti applications sharing the same data model and cubes (you can look at that in terms of description of the ActivePivot Manager within the Atoti application).
    • Multiple Atoti applications using different data models.

In the last case, one needs to make sure there is no conflict when storing the associated metadata in the content service. That is, if you have two different types of Atoti application to deal with (two different data model descriptions) then you want two sets of metadata to coexist in the content service, each in different "directories". And then, you need the respective Atoti applications to know where (in terms of directory) to look for the metadata.

This can be achieved by assigning a prefix to each type of Atoti application. Note that by default, the prefix is pivot. That is the name of the directory under which you would normally find metadata in the content service if you have done nothing special (explicit) with configuring a prefix when defining the content service you use on Atoti application.

Below is an example on how to define a specific prefix:

@Bean
public IActivePivotContentService activePivotContentService(
final IContentService contentService) {
return new ActivePivotContentServiceBuilder()
.with(IContentService.prefixed(contentService, "myActivePivotTypeA"))
.withoutCache()
.needInitialization("ROLE_USER", "ROLE_USER")
.build();
}

This will include both the myActivePivotTypeA and pivot prefixes, and so all data will be stored under the /myActivePivotTypeA/pivot/ directory.

Security

Each file in a content service has associated permissions:

  • The owner is the role for which users have read/write access to the file.
  • The reader is the role for which users have read-only access to the file.
  • If one does not belong to either the reader or owner role, one does not have any access to the file.

Users with read rights on given files or directories can do the following:

  • Read the content of a file.
  • List all files and directories within a directory.
  • Know that the parent directory of a file exists. Note that read rights are still required on the parent itself to access its details.

Users with owner rights on given files or directories can do all the previous operations in addition to the following:

  • Create a file inside a directory.
  • Edit or delete a file.
  • Delete a directory. This also requires ownership over all its descendants.
  • Edit permissions of a file or directory. Non-root users cannot update permissions to new lists of roles if they do not belong to any of the roles.

Additionally, a special "root" role exists and grants ownership rights to its members over all entries of the content service. Its name can be configured using the activeviam.contentservice.root property. See this page for more information.

Admin UI

A user interface to browse the content in the content service and the datastore is available (if configured as such) wherever the content service API has been exposed/deployed.

For example, in the Atoti Sandbox, the Admin UI is exposed at <root URL>/admin/ui, where <root URL> = <host>:<port>/<application path>. The host and port to use are those of the machine containing the content server: the same machine containing Atoti Server when using an embedded content service, or the remote machine when using a remote content service.

The Admin UI allows one to see all the content one has access to (a.k.a. specifically, given the access rights one has been granted).
One will be able to see the content of the file if and only if one has read access to it, and to modify its permissions and content, if and only if one has write access to it.

In the following example we see how the Admin UI allows a super-user to read the permissions on branches.

Admin UI Example - branches

Entitlements

Atoti entitlements are stored in the content service. Entitlements that are modified through the ActivePivot content service are immediately available to the Atoti application. However, entitlements that are edited directly in the content service are ignored by a running Atoti application, because the entitlements of the Atoti application are cached by default. There are solutions to overcome that:

  • You can set a time to live for the cache
  • You can reset the cache using the provided "Clear cache" JMX Operation

Import and Export

It is possible to perform imports in a content service using the REST API or the ContentServiceSnapshotter.
In the case of a content service with persistence in a database, the import speed greatly depends on the network speed between the machine hosting the content service and the database, and on the database performance itself. For example if the content is persisted in an Azure database, the import speed will be optimized if the content service is hosted in an Azure VM and if the number of DTUs of the database is temporarily augmented for the time of the import.

An import parameter for the POST method of the REST API allows to import a whole content subtree in a single bulk operation, which significantly improves performance - it is used in the ContentServiceSnapshotter in the case of a remote content service.

The export is simply the GET method of the REST API.

Content service APIs

Machines containing a content service can exposes a REST API and a WebSocket API to interact with it. See their respective pages for more information.