1. Introduction

All properties that are available to store metadata for DMS objects are defined in a schema. Some properties are pre-defined system properties.

In this tutorial we will define our own properties and object types. Thus, we will be able to create DMS objects having those properties filled with individual values.

Our example scenario will be a pet shop app. We will create an app schema with properties to describe pets, enclosures and their relationships.

2. Requirements

Please work through the following tutorials to get prepared:

3. Java Libraries

Import the following Java libraries (if not already done).

Used Java Libraries
import okhttp3.*;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.io.File;

4. Variables with Login and Content Types Configuration

Specify your access credentials and content type configurations (if not already done).

Definition of Variables
public static final String username = "root";
public static final String userpassword = "changeme";
public static final String auth = "Basic "+ Base64.getEncoder().encodeToString((username+":"+userpassword).getBytes());
public static final String tenant = "myfirsttenant";
public static final String baseUrl = "http://123.456.78.9:30080";

public static final MediaType XML = MediaType.parse("application/xml; charset=utf-8");

5. Client

To send our requests, we again use the Java client.

Client with Cookie Handling
try {
    CookieJar cookieJar = new JavaNetCookieJar(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
    OkHttpClient client = new OkHttpClient.Builder().cookieJar(cookieJar).build();

} catch (Exception e) {
    e.printStackTrace();

}

6. Retrieving the Applied Schema

The currently applied schema can be retrieved with a GET request to the URL /api/dms/schema.

This schema contains all property and object type definitions that are currently available within your tenant. Those definitions are merged from the following schema sources:

  • global schema containing pre-defined system properties and object types

  • tenant schema containing properties and object types defined specifically for your tenant

  • app schemata containing properties and object types defined specifically for an app

Retrieving the Applied Schema
Request getSchemaRequest = new Request.Builder()
                .header("Authorization", auth)
                .header("X-ID-TENANT-NAME", tenant)
                .header("Accept", "application/xml")
                .url(baseUrl + "/api/dms/schema/native")
                .get()
                .build();

We use the Accept header to specify the output format of the schema information.

The output is looks similar to the following excerpt:

Example excerpt from an Applied Schema
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/">
    <version>0</version>
    <lastModificationDate>2025-10-06T19:04:37.877Z</lastModificationDate>
    <propertyIdDefinition>
        <id>system:objectId</id>
        <description>Id of the object</description>
        <propertyType>id</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyIdDefinition>
    <propertyIdDefinition>
        <id>system:baseTypeId</id>
        <description>Id of the base object-type for the object</description>
        <propertyType>id</propertyType>
        <cardinality>single</cardinality>
        <required>false</required>
    </propertyIdDefinition>
    ...
</schema>

7. Defining Properties

We now need to think about the properties we want to define for our pet shop app. The property definitions are located at the top of the schema resource file.

Property Definitions
<?xml version="1.0" encoding="utf-8"?>
<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/ dmsCloud-schema.xsd">
    <propertyIntegerDefinition>
        <id>appPetshop:capacity</id>
        <description>maximum number of animals to live in the enclosure</description>
        <propertyType>integer</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyIntegerDefinition>
    <propertyStringDefinition>
        <id>appPetshop:staffInCharge</id>
        <description>name of the responsible shop employees</description>
        <propertyType>string</propertyType>
        <cardinality>multi</cardinality>
        <required>true</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appPetshop:breed</id>
        <description>name of the pet's breed</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyStringDefinition>
    <propertyStringDefinition>
        <id>appPetshop:species</id>
        <description>name of the pet's species</description>
        <propertyType>string</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyStringDefinition>
    <propertyDecimalDefinition>
        <id>appPetshop:price</id>
        <description>price for the pet in Euro</description>
        <propertyType>decimal</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyDecimalDefinition>
    <propertyDateTimeDefinition>
        <id>appPetshop:dateOfBirth</id>
        <description>the pet's date of birth</description>
        <propertyType>datetime</propertyType>
        <cardinality>single</cardinality>
        <required>true</required>
    </propertyDateTimeDefinition>
</schema>

8. Defining Secondary Object Types

Now we can define the object types pet and enclosure. We define them as secondary object types. This means, that we can assign (or remove) those types later to (from) already existing DMS objects of the type system:document.

<typeSecondaryDefinition>
    <id>appPetshoppet</id>
    <baseId>system:secondary</baseId>
    <propertyReference>appPetshopbreed</propertyReference>
    <propertyReference>appPetshopspecies</propertyReference>
    <propertyReference>appPetshopdateOfBirth</propertyReference>
    <propertyReference>appPetshopprice</propertyReference>
    <contentStreamAllowed>allowed</contentStreamAllowed>
</typeSecondaryDefinition>
<typeSecondaryDefinition>
    <id>appPetshopenclosure</id>
    <baseId>system:secondary</baseId>
    <propertyReference>appPetshopcapacity</propertyReference>
    <propertyReference>appPetshopstaffInCharge</propertyReference>
    <contentStreamAllowed>allowed</contentStreamAllowed>
</typeSecondaryDefinition>

9. Defining a Relationship Object Type

The relationship object type definition is introduced before the secondary object type definitions.

<typeRelationshipDefinition>
<id>appPetshoppetLivesIn</id>
    <baseId>system:relationship</baseId>
    <allowedSourceType>
        <objectTypeReference>appPetshop:pet</objectTypeReference>
    </allowedSourceType>
    <allowedTargetType>
        <objectTypeReference>appPetshop:enclosure</objectTypeReference>
    </allowedTargetType>
</typeRelationshipDefinition>

10. Validating a Schema

A POST request for the URL /api/system/apps/{app}/schema/validate can be used to verify that a schema is valid. This requires a schema; in the example, under the path ./schemaToValidate.xml. The schema is sent as a multi-part in the body of the request.

Validating a Schema
RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", "schema.xml", RequestBody.create(XML, new File("./src/main/resources/schemaAppPetshop.xml")))
        .build();

Request validateSchemaRequest = new Request.Builder()
        .header("Authorization", auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/system/apps/petshop/schema/validate")
        .post(requestBody)
        .build();

The response to this request contains an HTTP status code and the validation result in JSON format. You can simply output this to the console after the request was called using an OkHttpClient instance.

Console Output of the Validation Result
Response validationResponse = client.newCall(validateSchemaRequest).execute();
System.out.println(validationResponse.code());
String validationResponseAsString = validationResponse.body().string();
System.out.println(validationResponseAsString);

In the case of a valid schema, the response contains the HTTP status code 200 and the validation result is an empty list, meaning it does not contain any validation errors.

Result of a Successful Validation
{
    "validationErrors": []
}

If, however, the schema is not valid, the response contains the HTTP status code 422 and there is at least one validation error.

Result of an Unsuccessful Validation
{
    "validationErrors": [{
        "message": "Invalid property reference 'name' in type definition 'email'."
    }]
}

11. Importing a New Schema

A new schema can be imported with the POST request to the URL /api/admin/schema. The endpoint behaves similar to the validation endpoint, meaning the HTTP status code of the answer tells you if the schema is valid and the answer contains a validation result. The difference is that if the validation is successful, the schema is stored and activated in the system.

Importing a Schema
String filename = "./schemaToImport.xml";

RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", "schema.xml", RequestBody.create(XML, new File("./src/main/resources/schemaAppPetshop.xml")))
        .build();

Request validateSchemaRequest = new Request.Builder()
    .header("Authorization", auth)
        .header("X-ID-TENANT-NAME", tenant)
        .url(baseUrl + "/api/system/apps/petshop/schema")
        .post(requestBody)
        .build();

The further use of the request is analogous to the validation of a schema described in the previous section.

12. Changing the Schema

Typically, you rarely want to import a completely new schema. Often you only want to extend the active schema with object types or properties or make small changes. This can be done with the help of the three preset endpoints:

  1. Fetch the schema to be changed and save it locally in an XML file.

  2. Make the desired changes to the XML file and verify with the validation endpoint whether the new version of the schema is still valid.

  3. Import the changed, valid schema

13. Summary

A complete code example can be found in this git repository.