Table of Contents
This chapter presents the concepts of schemas and document types, which are used to define new documents in Nuxeo EP 5.
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.
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
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.
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.
<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.
<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.
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.
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.
<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
.
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.
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>