Schemas and Documents

Table of Contents

5.1. Introduction
5.1.1. Concepts
5.2. Schemas
5.3. Core Document Types
5.4. ECM Document Types
5.4.1. Label and Icon
5.4.2. Default view
5.4.3. Layout
5.4.4. Containment rules
5.4.5. Hidden cases
5.4.6. Summary

5.1. Introduction

This chapter presents the concepts of schemas and document types, which are used to define new documents in Nuxeo EP 5.

5.1.1. Concepts

In Nuxeo EP 5, a fundamental entity is the document. A file, a note, a vacation request, an expense report, but also a folder, a forum, can all be thought of as documents. Objects that contain documents, like a folder or a workspace, are also themselves documents.

Any given document has a document type. The document type is specified at creation time, and does not change during the lifetime of the document. When referring to the document type, a short string is often used, for instance “Note” or “Folder”.

A document type is the grouping of several schemas. A schema represents the names and structure (types) of a set of fields in a document. For instance, a commonly-used schema is the Dublin Core schema, which specifies a standard set of fields used for document metadata like the title, description, modification date, etc.

To create a new document type, we start by creating one ore more schemas that the document type will use.

The schema is defined in a .xsd file (which obeys the standard XML Schema syntax) and is registered by a contribution to a schema extension point.

The document type is registered through a contribution to another doctype extension point, and will specify which schemas it uses. We also register the document type as a high-level type used by the EJB and rendering layers.

“Core” document types and “ECM” component types should not be confused. The former live in the core Nuxeo EP packages, the latter belong to the high level components. Apart from their definition, most of the uses of "document types" refer to the “ECM” kind.

5.2. Schemas

A schema describes the names and types of some fields. The name is a simple string, like "title", and the type describes what kind of information it stores, like a string, an integer or a date.

First, we create a schema in the resources/schemas/sample.xsd file:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://project.nuxeo.org/sample/schemas/sample/">
  <xs:element name="sample1" type="xs:string"/>
  <xs:element name="sample2" type="xs:string"/>
</xs:schema>

This schema defines two things:

  • an XML namespace that will be associated with the schema,

  • two elements and their type.

The two elements are sample1 and sample2. They are both of type xs:string, which is a standard type defined by the XML Schema specification.

This schema has to be referenced by a configuration file so that the system knows it has to be read. The configuration file will be placed in OSGI-INF/core-types-contrib.xml (the name is just a convention):

<?xml version="1.0"?>
<component name="org.nuxeo.project.sample.coreTypes">
  <extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema">
    <schema name="sample" src="schemas/sample.xsd"/>
  </extension>
</component>

We name our schema sample, and the .xsd schema was placed under resources/ which means that at runtime, it will be available directly from the Jar, therefore we reference it through the path schemas/sample.xsd. The schema is registered through an extension point of the Nuxeo component org.nuxeo.ecm.core.schema.TypeService named schema. Our own extension component is given a name, org.nuxeo.project.sample.coreTypes, which is not very important as we only contribute to existing extension points and don't define new ones.

Finally, we tell the system that the OSGI-INF/core-types-contrib.xml file has to be read, by mentioning it in the Nuxeo-Component part of the META-INF/MANIFEST.MF file of our bundle:

Manifest-Version: 1.0 
Bundle-ManifestVersion: 1 
Bundle-Name: NXSample project 
Bundle-SymbolicName: org.nuxeo.project.sample;singleton:=true 
Bundle-Version: 1.0.0 
Bundle-Vendor: Nuxeo 
Require-Bundle: org.nuxeo.runtime, 
 org.nuxeo.ecm.core.api, 
 org.nuxeo.ecm.core 
Provide-Package: org.nuxeo.project.sample 
Nuxeo-Component: OSGI-INF/core-types-contrib.xml 

5.3. Core Document Types

By itself, the schemas is not very useful. We associate it with a new “core” document type that we will be creating. In the same OSGI-INF/core-types-contrib.xml as above, we add the following:

<?xml version="1.0"?>
<component name="org.nuxeo.project.sample.coreTypes">
  <extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema">
    <schema name="sample" src="schemas/sample.xsd" prefix="smp"/>
  </extension>
  <extension target="org.nuxeo.ecm.core.schema.TypeService" point="doctype">
    <doctype name="Sample" extends="Document">
      <schema name="common"/>
      <schema name="dublincore"/>
      <schema name="sample"/>
    </doctype>
  </extension>
</component>

The document type is defined through a contribution to an other extension point, doctypes, of the same extension component as before, org.nuxeo.ecm.core.schema.TypeService. We specify that our document type, Sample, will be an extension of the standard system type Document, and that it will be composed of three schemas, two standard ones and our specific one.

The Dublin Core schema that we use already contains standard metadata fields, like a title, a description, the modification date, the document contributors, etc. Adding it to our document type ensures that a minimal level of functionality will be present.

5.4. ECM Document Types

After the “core” document type, we need to create the “ECM” document type. This is done through a contribution to another extension point, that we place in the OSGI-INF/ecm-types-contrib.xml, the basic structure of this file is:

<?xml version="1.0"?>
<component name="org.nuxeo.project.sample.ecm.types">
  <extension target="org.nuxeo.ecm.platform.types.TypeService" point="types">
    <type id="Sample" coretype="Sample">
      ...
    </type>
  </extension>
</component>

As of this writing, the document type id has to be the same as the underlying core type; this restriction may be lifted in the future. The type element will contain all the information for this type, this is described below.

This extension file is added to META-INF/MANIFEST.MF so that it will be taken into account by the deployment mechanism:

Nuxeo-Component: OSGI-INF/core-types-contrib.xml,
 OSGI-INF/ecm-types-contrib.xml

Inside the type element, we provide various information, described below.

5.4.1. Label and Icon

<label>Sample document</label>
<icon>/icons/file.gif</icon>

The label and icon are used by the user interface, for instance in the creation page when a list of possible types is displayed. The icon is also used whenever a list of document wants to associate an icon with each.

5.4.2. Default view

<default-view>view_documents</default-view>

The default view specifies the name of the Facelet to use for this document if nothing is specified. This corresponds to a file that lives in the webapp, in this case view_documents.xhtml is a standard view defined in the base Nuxeo bundle, that takes care of displaying available tabs, and the document body according to the currently selected type. Changing it is not advised unless extremely nonstandard rendering is needed.

5.4.3. Layout

5.4.3.1. Configuration

Here is the new layout configuration:

<layouts mode="any">
  <layout>heading</layout>
  <layout>note</layout>
</layouts>

Layouts are defined in a given mode (default modes are "create", "edit" and "view") ; layouts in the "any" mode will be merged with layouts defined for specific modes.

The layout names refer to layouts defined on another extension point. Please see the layouts section for more information.

5.4.3.2. Deprecated configuration

Here is the old layout configuration that has been replaced by the above. If present, it is used instead of the new configuration for compatibility purposes.

<layout>
  <widget jsfcomponent="h:inputText"
    schemaname="dublincore" fieldname="title"
    required="true" />
  <widget jsfcomponent="h:inputTextarea"
    schemaname="dublincore" fieldname="description" />
  <widget jsfcomponent="h:inputText"
    schemaname="sample" fieldname="sample1" />
  <widget jsfcomponent="h:inputText"
    schemaname="sample" fieldname="sample2" />
</layout>

This section defines a series of widgets, that describe what the standard layout of this document type will be. A layout is a series of widgets, which make the association between the field of a schema with a JSF component.

The layout is used by the standard Nuxeo modification and summary views, to automatically display the document according to the layout rules. Note that the layout system is still young and is subject to minor changes in the future. Here we define four widgets, displayed as simple input fields or as a text area.

5.4.4. Containment rules

<type id="Folder" coretype="Folder">
  <subtypes>
    <type>Sample</type>
  </subtypes>
</type>
<type id="Workspace" coretype="Workspace">
  <subtypes>
    <type>Sample</type>
  </subtypes>
</type>

This contributes a rule to an already existing type, Folder. The subtypes element specifies which types can be created inside the type in which the element is embedded.

Here, we specify that our Sample type can be created in a Folder and a Workspace.

5.4.5. Hidden cases

The goal is to contribute a way to define hidden cases for the subtypes definition. A syntax like the following can be used:

<type id="Workspace"> 
  <subtypes> 
    <type>Workspace</type> 
    <type hidden="create">Folder</type> 
    <type>File</type> 
    <type>Note</type> 
  </subtypes> 
</type>

If more than one hidden cases needs to be defined, then a syntax like the following can be used:

<type id="Workspace"> 
  <subtypes> 
    <type>Workspace</type> 
    <type hidden="create, paste">Folder</type> 
    <type>File</type> 
    <type>Note</type> 
  </subtypes> 
</type>

The hidden cases are stored in a list ([create, paste] for the above example), so if a check is needed for a hidden case, then the hidden cases list ought to be verified if contains that particular case.

5.4.6. Summary

The final OSGI-INF/ecm-types-contrib.xml looks like:

<?xml version="1.0"?>
<component name="org.nuxeo.project.sample.ecm.types">
  <extension target="org.nuxeo.ecm.platform.types.TypeService" point="types">
    <type id="Sample" coretype="Sample">
      <label>Sample document</label>
      <icon>/icons/file.gif</icon>
      <default-view>view_documents</default-view>
      <layout>
        <widget jsfcomponent="h:inputText"
          schemaname="dublincore" fieldname="title"
          required="true" />
        <widget jsfcomponent="h:inputTextarea"
          schemaname="dublincore" fieldname="description" />
        <widget jsfcomponent="h:inputText"
          schemaname="sample" fieldname="sample1" />
        <widget jsfcomponent="h:inputText"
          schemaname="sample" fieldname="sample2" />
      </layout>
    </type>
    <type id="Folder" coretype="Folder">
      <subtypes>
        <type>Sample</type>
      </subtypes>
    </type>
    <type id="Workspace" coretype="Workspace">
      <subtypes>
        <type>Sample</type>
      </subtypes>
    </type>
  </extension>
</component>