Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Schema extension is one of the core features of CollectionSpace. It is anticipated that CollectionSpace application could be customized by extending base schema for a museum domain. The multi-tenant architecture explains why Nuxeo is selected to realize this requirement. The following sections describe the anatomy of a (Nuxeo 5.2 GA) document type representing a CollectionSpace entity called CollectionObject.

There are three aspects concerning a Nuxeo document type.

  1. Definition
  2. Packaging
  3. Deployment

Following sections describe each of these aspects with the help of an example document type for CollectionObject.

Panel
titleOn This Page
Table of Contents
maxLevel5

Definition

Wiki Markup
{multi-excerpt:name=schema extension core type def}
h4. Core Type Definition

The core type definition describes constituent XML schemas of a document type. In the example of CollectionObject (in [Release 0.3]), the *CollectionObject* document type consists of the following 4 schemas. In Nuxeo's terms, these are called *fragments* of a document type. We will be using terms components, parts and fragments interchangeably in this document.


{NewCode:language=xml|title=core-types-contrib.xml|controls=true|linenumbers=true}
<?xml version="1.0"?>
<component name="org.collectionspace.collectionobject.coreTypes">
    <extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema">
        <schema name="collectionobjects_common" prefix="collectionobjects_common" src="schemas/collectionobjects_common.xsd"/>
        <schema name="collectionobjects_anthropology" prefix="collectionobjects_anthropology" src="schemas/collectionobjects_anthropology.xsd"/>
    </extension>
    <extension target="org.nuxeo.ecm.core.schema.TypeService" point="doctype">
        <doctype name="CollectionObject" extends="Document">
            <schema name="common"/>
            <schema name="dublincore"/>
            <schema name="collectionobjects_common"/>
            <schema name="collectionobjects_anthropology"/>
        </doctype>
    </extension>
</component>
{NewCode}

As shown in the type definition above, the four parts are:

# collectionobjects_common (common entity schema for CollectionObject entity)
# collectionobjects_anthropology (test schema for anthropology museum)
# dublincore (not used by collectionspace, might be removed in future)
# common (just for manipulating documents using Nuxeo's web application during debug and testing, not used by the CollectionObjects service)

Location: OSGI-INF/core-types-contrib.xml

h5. XML Schema(s)

h6. collectionobjects_common.xsd
{newcode:language=xml|title=collectionobjects_common.xsd|controls=true|linenumbers=true}<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ns="http://collectionspace.org/services/collectionobject/"
    xmlns="http://collectionspace.org/services/collectionobject/"
    targetNamespace="http://collectionspace.org/services/collectionobject/"
    version="0.1">

    <xs:element name="objectNumber" type="xs:string"/>
    <xs:element name="otherNumber" type="xs:string"/>
    <xs:element name="briefDescription" type="xs:string"/>
    <xs:element name="comments" type="xs:string"/>
    <xs:element name="distFeatures" type="xs:string"/>
    <xs:element name="objectName" type="xs:string"/>
    <xs:element name="responsibleDept" type="xs:string"/>
    <xs:element name="title" type="xs:string"/>
    
</xs:schema>{newcode}
Location: schemas/collectionobjects_common.xsd

h6. collectionobjects_anthropology.xsd
{newcode:language=xml|title=collectionobjects_anthropology.xsd|controls=true|linenumbers=true}<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ns="http://collectionspace.org/services/collectionobject/domain/anthropology"
    xmlns="http://collectionspace.org/services/collectionobject/domain/anthropology"
    targetNamespace="http://collectionspace.org/services/collectionobject/domain/anthropology"
    version="0.1">

    <xs:element name="inscriber" type="xs:string" />
    <xs:element name="inscriptionLanguage" type="xs:string"/>
    <xs:element name="inscriptionDescription" type="xs:string"/>
    <xs:element name="inscriptionDate" type="xs:dateTime"/>
    <xs:element name="inscriptionMethod" type="xs:string"/>
    
</xs:schema>{newcode}
  
*Note* The schemas do not use complex types. This is due to limitations of the Nuxeo Query Language (NXQL). Also, note that the example for anthropology domain schema is just an example used here to explain the concept, it does not reflect the real anthropology domain schema for the collection object. 

{multi-excerpt}

Type definition for Nuxeo ECM

Corresponding to the core type definition, Nuxeo requires an ECM type definition to relate the new core type to one or more existing core types. The following ECM type definition for CollectionObject core type indicates that it has two parent core types: Folder and Workspace. That means a document for CollectionObject could be created under Folder or Workspace document types.

Code Block
<?xml version="1.0"?>
<component name="org.collectionspace.collectionobject.ecm.types">
  <extension target="org.nuxeo.ecm.platform.types.TypeService" point="types">
    <type id="CollectionObject" coretype="CollectionObject">
      <label>org.collectionspace.collectionobject</label>
      <!--icon>/icons/file.gif</icon-->
      <default-view>view_documents</default-view>

      <layouts mode="any">
        <layout>heading</layout>
        <layout>collectionobject</layout>
      </layouts>        
    </type>

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

  </extension>
</component>

Location: OSGI-INF/ecm-types-contrib.xml

Layout (only for Nuxeo webapp)

Layout definition is only required to indicate to the Nuxeo web application, how to lay out the new core type definition. CollectionSpace service team uses the Nuxeo webapp for verification, debug and testing purposes only.

Code Block
<?xml version="1.0"?>

<component name="org.collectionspace.collectionobject.layouts.webapp">

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="layouts">

    <layout name="collectionobject">
      <templates>
        <template mode="any">/layouts/layout_default_template.xhtml</template>
      </templates>
      <rows>
        <row><widget>objectNumber</widget></row>
        <row><widget>otherNumber</widget></row>
        <row><widget>briefDescription</widget></row>
        <row><widget>comments</widget></row>
        <row><widget>distFeatures</widget></row>
        <row><widget>objectName</widget></row>
        <row><widget>responsibleDept</widget></row>
        <row><widget>title</widget></row>
      </rows>

      <widget name="objectNumber" type="text">
        <labels>
          <label mode="any">objectNumber</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field schema="collectionobject">objectNumber</field>
        </fields>
        <properties widgetMode="edit">
          <property name="styleClass">dataInputText</property>
        </properties>
      </widget>
      
      ...

    </layout>
  </extension>
</component>

Note The example file shown above has been truncated for succinct description.

Location: OSGI-INF/layouts-contrib.xml

Packaging

A Nuxeo document type is packaged as an OSGI bundle. The following sections describe the directory structure, manifest and Maven build task.

Directory structure

The constituent parts of a document type as described above should be laid out in directories as shown below (under nuxeo-platform-cs-collectionobject).

Code Block

3rdparty
|-- pom.xml
`-- nuxeo-platform-cs-collectionobject
    |-- pom.xml
    |-- src
    |   `-- main
    |   |   `-- resources
    |   |       `-- META-INF
    |   |       |   `-- MANIFEST.MF
    |   |       `-- OSGI-INF
    |   |       |   `-- core-types-contrib.xml
    |   |       |   `-- ecm-types-contrib.xml
    |   |       |   `-- layout-contrib.xml
    |   |       `-- schemas
    |   |       |   `-- collectionobjects_common.xsd
    |   |       |   `-- collectionobjects_anthropology.xsd

OSGI manifest - MANIFEST.MF

As mentioned earlier, a Nuxeo document type is packaged and deployed as an OSGI bundle. The manifest for the document type describes the version, namespace, required bundles and components of the document type as shown below.

Code Block
Manifest-Version: 1.0 
Bundle-ManifestVersion: 1 
Bundle-Name: NuxeoCS
Bundle-SymbolicName: org.collectionspace.collectionobject;singleton:=true 
Bundle-Version: 1.0.0
Bundle-Localization: plugin
Bundle-Vendor: Nuxeo 
Require-Bundle: org.nuxeo.runtime, 
 org.nuxeo.ecm.core.api, 
 org.nuxeo.ecm.core,
 org.nuxeo.ecm.core.api,
 org.nuxeo.ecm.platform.types.api,
 org.nuxeo.ecm.platform.versioning.api,
 org.nuxeo.ecm.platform.ui,
 org.nuxeo.ecm.platform.forms.layout.client,
 org.nuxeo.ecm.platform.publishing.api,
 org.nuxeo.ecm.platform.ws 
Provide-Package: org.collectionspace.collectionobject
Nuxeo-Component: OSGI-INF/core-types-contrib.xml,
 OSGI-INF/ecm-types-contrib.xml,
 OSGI-INF/layouts-contrib.xml
Maven build

Following maven build task describes how to package a document type.

Code Block
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <archive>
            <manifestFile> src/main/resources/META-INF/MANIFEST.MF </manifestFile>
            <manifestEntries>
              <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

Deployment

For CollectionSpace, the document type is deployed into Nuxeo repository backed by MySQL datastore. The following sections describe how a document type and its components (or fragments) are mapped into various MySQL tables.

Wiki Markup
{multi-excerpt:name=schema extension sql mapping}
h4. RDBMS Mapping

Nuxeo creates a table for each sub-component (or fragment) of a document type. The following tables represent each fragment of the CollectionObject document type.

# collectionobjects_common
# collectionobjects_anthropology
# dublincore
# common

If there are schemas (such as common and dublincore in the example above) that are shared between various document types, all those document types share the same table schemas for these base types. The columns of a table representing each fragment are all the single-valued properties of the corresponding schema. Multi-valued properties are stored in a separate table. 

h5. Document type fragments

Following shows the table for the collectionobjects_common fragment.

{NewCode}
mysql> describe collectionobjects_common;
Current database: nuxeo

+------------------+-------------+------+-----+---------+-------+
| Field            | Type        | Null | Key | Default | Extra |
+------------------+-------------+------+-----+---------+-------+
| id               | varchar(36) | NO   | PRI | NULL    |       |
| title            | text        | YES  |     | NULL    |       |
| responsibledept  | text        | YES  |     | NULL    |       |
| objectname       | text        | YES  |     | NULL    |       |
| distfeatures     | text        | YES  |     | NULL    |       |
| objectnumber     | text        | YES  |     | NULL    |       |
| othernumber      | text        | YES  |     | NULL    |       |
| briefdescription | text        | YES  |     | NULL    |       |
| comments         | text        | YES  |     | NULL    |       |
+------------------+-------------+------+-----+---------+-------+
{NewCode}

All the fragments of a document type are related by using the same identifier (id). For example, select a fragment reflecting the common entity of the CollectionObject document type from the _collectionobjects_common_ table as follows.

{NewCode}
mysql> select id, objectname, objectnumber from collectionobjects_common limit 1;

+--------------------------------------+--------------------------+----------------------------+
| id                                   | objectname               | objectnumber               |
+--------------------------------------+--------------------------+----------------------------+
| 000c022a-fffb-4aa8-95a9-e7bbae6b28a1 | objectName-1248890988981 | objectNumber-1248890988981 |
+--------------------------------------+--------------------------+----------------------------+

{NewCode}

You could find the corresponding _dublincore_ fragment using the same id, i.e. _000c022a-fffb-4aa8-95a9-e7bbae6b28a1_ as that of the collectionobject fragment as follows from the _dublincore_ table. 

{NewCode}

mysql> select id, title, creator, created from dublincore where id='000c022a-fffb-4aa8-95a9-e7bbae6b28a1';

+--------------------------------------+----------------------------------+---------+---------------------+
| id                                   | title                            | creator | created             |
+--------------------------------------+----------------------------------+---------+---------------------+
| 000c022a-fffb-4aa8-95a9-e7bbae6b28a1 | CollectionSpace-CollectionObject | system  | 2009-07-29 11:09:49 |
+--------------------------------------+----------------------------------+---------+---------------------+

{NewCode}


Question is: how Nuxeo traverses these various tables at runtime?

{multi-excerpt:name=schema extension sql query}

h5. Searching for fragments - The hierarchy table 

The hierarchy table represents the containment hierarchy between various nodes for a document in the Nuxeo repository. A document root could be considered one such node.

{NewCode}
mysql> describe hierarchy;
+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| id            | varchar(36)  | NO   | PRI | NULL    |       |
| parentid      | varchar(36)  | YES  | MUL | NULL    |       |
| pos           | int(11)      | YES  |     | NULL    |       |
| name          | varchar(255) | YES  |     | NULL    |       |
| isproperty    | bit(1)       | YES  |     | NULL    |       |
| primarytype   | varchar(255) | YES  |     | NULL    |       |
| ischeckedin   | bit(1)       | YES  |     | NULL    |       |
| baseversionid | varchar(36)  | YES  |     | NULL    |       |
| majorversion  | int(11)      | YES  |     | NULL    |       |
| minorversion  | int(11)      | YES  |     | NULL    |       |
+---------------+--------------+------+-----+---------+-------+
{NewCode}

Now select a root document node for a CollectionObject document type as follows. 

{NewCode}

mysql> select id, parentid, primarytype from hierarchy where primarytype='CollectionObject' limit 1;

+--------------------------------------+--------------------------------------+------------------+
| id                                   | parentid                             |primarytype      |
+--------------------------------------+--------------------------------------+------------------+
| 000c022a-fffb-4aa8-95a9-e7bbae6b28a1 | 58a709de-f582-4b1a-aada-eb4e52f902cb |CollectionObject |
+--------------------------------------+--------------------------------------+------------------+

{NewCode}

*Note* to explain the example better, we have deliberately shown the result above that relates to the collectionobject instance (id=000c022a-fffb-4aa8-95a9-e7bbae6b28a1) being discussed here.

When retrieving a document by its id, the primary type is consulted first in the hierarchy table. If a value is found, all applicable fragments are deduced (from perhaps the cached document type information in Nuxeo repository runtime?), to give full information about all the fragment tables (e.g. common and dublincore) that apply to the document.

A parent could be deduced by using the parent id and executing a similar query. The following shows that the parent of CollectionObject is a Workspace.

{NewCode}

mysql> select id, parentid, primarytype from hierarchy where id='58a709de-f582-4b1a-aada-eb4e52f902cb';

+--------------------------------------+--------------------------------------+-------------+
| id                                   | parentid                             |primarytype |
+--------------------------------------+--------------------------------------+-------------+
| 58a709de-f582-4b1a-aada-eb4e52f902cb | 5e404539-0e0c-405e-8b03-49b90ecb99dd |Workspace   |
+--------------------------------------+--------------------------------------+-------------+
{NewCode}
{multi-excerpt}

JBoss domain

Document type packages
Schema files

When a document type package is deployed in the Nuxeo domain, it creates necessary tables in the SQL storage of the repository as shown above and it also copies the constituent XML schema files on the root directory of the domain as shown below. The following information is provided here only for debugging purposes. It is not advisable to modify these files by hand.

Code Block

default
|-- data
    |-- NXRuntime
    |   `-- schemas
    |   |   `-- common.xsd
    |   |   `-- collectionobjects_common.xsd
    |   |   `-- collectionobjects_anthropology.xsd
    |   |   `-- dublincore.xsd

Wiki Markup
{multi-excerpt:name=schema extension access}

h3. Document access

There are two ways to manage and access documents in Nuxeo.

# Using [DocumentModel|http://doc.nuxeo.org/5.2/apidocs/org/nuxeo/ecm/core/api/DocumentModel.html] APIs
# Search and query using [NXQL|http://doc.nuxeo.org/5.2/books/nuxeo-book/html/search-service.html]

h4. Using DocumentModel APIs

The Nuxeo document model is a serializable representation of a core document. It is made from several data models, each data model is bound to a schema. 

h5. Create

{newcode:language=java|title=document model:create}

String nuxeoWspaceId = "your workspace uuid"; //e.g. id of CollectionObjects workspace
String docType = "CollectionObject"; // e.g. your document type name

RepositoryInstance repoSession = getRepositorySession(); //assumed: how to get repository session
DocumentRef nuxeoWspace = new IdRef(nuxeoWspaceId);
DocumentModel wspaceDoc = repoSession.getDocument(nuxeoWspace);
String wspacePath = wspaceDoc.getPathAsString();
//give our own ID so PathRef could be constructed later on
String id = IdUtils.generateId(UUID.randomUUID().toString());
DocumentModel doc = repoSession.createDocumentModel(wspacePath, id, docType);
...
//fill up properties for constituent data models
...
doc = repoSession.createDocument(doc);

repoSession.save();
{newcode}

h5. Get
{newcode:language=java|title=document model:get}

String id = "id of the document you want to retrive";
RepositoryInstance repoSession = getRepositorySession(); //assumed: how to get repository session
//build path ref for collectionobjects in default_domain assigned to default tenant
DocumentRef docRef = new PathRef("/default_domain" +
                "/workspaces" +
                "/CollectionObjects" + " +
                "/" + id);
DocumentModel doc = repoSession.getDocument(docRef);
{newcode}


h5. Delete
{newcode:language=java|title=document model:delete}

String id = "id of the document you want to retrive";
RepositoryInstance repoSession = getRepositorySession(); //assumed: how to get repository session
//build path ref for collectionobjects in default_domain assigned to default tenant
DocumentRef docRef = new PathRef("/default_domain" +
                "/workspaces" +
                "/CollectionObjects" + " +
                "/" + id);
repoSession.removeDocument(docRef);
repoSession.save();
{newcode}


h4. Search and query using NXQL
{multi-excerpt}

References

  1. Nuxeo schemas and documents
  2. Nuxeo SQL Storage Specification
Recently Updated
labelsnuxeo, multi-tenancy