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).
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).
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.
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
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:
<?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.
<?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.
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.
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.
{
"validationErrors": []
}
If, however, the schema is not valid, the response contains the HTTP status code 422 and there is at least one validation error.
{
"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.
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:
-
Fetch the schema to be changed and save it locally in an XML file.
-
Make the desired changes to the XML file and verify with the validation endpoint whether the new version of the schema is still valid.
-
Import the changed, valid schema
13. Summary
A complete code example can be found in this git repository.