> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to configure a content service

This guide shows the steps to set up a [content service](../../content_server/cs_overview).

## Option 1: using Atoti Server Starter (recommended)

The recommended way to configure the content service is to use the [Atoti Server Starter](../../starters/atoti_starter).
Once it has been added to your project, a content service will automatically be created.
The content service can then be configured by setting the [relevant Spring properties](../../properties/Properties#atoti-server-starter-properties).

First, set the content service type to use as shown below.
By default, an in-memory content service is used.

```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
atoti:
  server:
    content-service:
      enabled-type: in_memory # in_memory | hibernate | remote
```

The following sections show additional configuration properties for each applicable type of content service.

### Hibernate content service

To use a content service backed by a database:

1. Make sure your database's JDBC driver is available at runtime.
   This example uses an [H2 database](https://www.h2database.com/html/main.html), so the following dependency needs to be added:
   ```xml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
   <dependency>
       <groupId>com.h2database</groupId>
       <artifactId>h2</artifactId>
   </dependency>
   ```
2. Set `atoti.server.content-service.enabled-type` to `hibernate`.
3. Use a configuration such as:
   ```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
   atoti.server.content-service.hibernate:
     url: jdbc:h2:mem:content_service;DB_CLOSE_DELAY=-1
     hibernate-options:
       # For available options, see:
       # https://docs.jboss.org/hibernate/orm/6.6/userguide/html_single/Hibernate_User_Guide.html#settings
       hibernate.show_sql: false
       hibernate.format_sql: false
       hibernate.globally_quoted_identifiers: false
     driver: org.h2.Driver
   ```

To use a different database, update the `url` and `driver` properties.

### Remote content service

To use a remote content service:

1. Set `atoti.server.content-service.enabled-type` to `remote`.
2. Use a configuration such as:
   ```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
   atoti.server.content-service.remote:
     uri: http://localhost:9091/activeviam/content
     max-connection-time: PT30M
     username: admin
   ```

## Option 2: manual bean declaration

An alternative to using the Atoti Server Starter is for your Spring configuration to define the appropriate beans.

### 1. Create an `IContentService`

The first bean required is of type `IContentService`.
`IContentService.builder()` can be used to create instances of `IContentService`.

The following sections give examples for each content service type.

#### In-memory content service

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IContentService contentService() {
  return IContentService.builder().inMemory().build();
}
```

#### Hibernate content service

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IContentService contentService() {
  final Properties properties = new Properties();
  properties.setProperty(
      AvailableSettings.JAKARTA_JDBC_URL, "jdbc:h2:mem:content_service;DB_CLOSE_DELAY=-1");
  properties.setProperty(AvailableSettings.JAKARTA_JDBC_DRIVER, "org.h2.Driver");
  properties.setProperty(AvailableSettings.SHOW_SQL, "false");
  properties.setProperty(AvailableSettings.FORMAT_SQL, "false");
  properties.setProperty(AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, "false");
  properties.setProperty(AvailableSettings.HBM2DDL_AUTO, Action.ACTION_CREATE);
  final Configuration config = new Configuration().addProperties(properties);
  return IContentService.builder().withPersistence().configuration(config).build();
}
```

To use database-level locks instead of Java locks, use the builder's `databaseLocks` method:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
return IContentService.builder()
    .withPersistence()
    .configuration(config)
    .databaseLocks(LockOptions.defaultOptions())
    .build();
```

#### Remote content service

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IContentService contentService(final IJwtService jwtService) {
  return RemoteContentServiceBuilder.create()
      .apiRootUri("http://localhost:9091/activeviam/content")
      .userAuthenthicator(new JwtAuthenticator(jwtService))
      .build();
}
```

### 2. Create an `IActivePivotContentService`

The second bean required is of type `IActivePivotContentService` and wraps the first bean.
`ActivePivotContentServiceBuilder` can be used to create instances of `IActivePivotContentService`.

One way to create this bean is shown in the example below.

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IActivePivotContentService activePivotContentService(
    final IContentService contentService) {
  return new ActivePivotContentServiceBuilder()
      .with(contentService)
      .withoutCache()
      .needInitialization("ROLE_USER", "ROLE_USER")
      .build();
}
```

In some cases such as when a single content service is used by multiple Atoti Servers, it may be useful to have each server use a different prefix.
One way to define such a prefix is shown below.
For more information, see [here](../../content_server/cs_overview#sharing-one-content-service-between-multiple-atoti-instances)

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Bean
public IActivePivotContentService activePivotContentService(
    final IContentService contentService) {
  return new ActivePivotContentServiceBuilder()
      .with(IContentService.prefixed(contentService, "myActivePivotTypeA"))
      .withoutCache()
      .needInitialization("ROLE_USER", "ROLE_USER")
      .build();
}
```
