CMIS Type Mutabilityproposal

Jay Brown / IBM

jay.brown @ us.ibm.com

Version: 0.4

Date: 9/30/2010

Purpose of proposal.

Suggest a simple design extension for the CMIS specification that will enable CMIS clients and applications to create their own custom metadata.

In keeping with the spirit of CMIS, it is not the intention of the Type Mutability capability to cover all possible aspects of type creation for all possible repository types. There will be aspects of type creation that will always need to be done with native APIs. However, if this simple set of capabilities is added, it will be possible for generic CMIS applications to setup their own required metadata, and clean up after themselves if uninstalled. The restrictions set forth in this document are to make it reasonably likely that any ECM system can comply with these requirements.

This document is not intended to be complete, but rather a starting point for a small group or subcommittee to work from to produce a complete document.

Type Mutability requirements:

  1. Must be optional and 100% backwards compatible with 1.0
  2. Must be implemented in a way such that is it obvious to someone familiar with CMIS 1.0 how these operations would be implemented. (e.g. POST to the ‘Types Children’ collection equates to a creation of a new type, etc. )
  3. Must allow an application to setup new types with associated new properties.
  4. Must allow an application to clean up types it has created. (i.e. for uninstall)
  5. Exposed schema changes will be confined to a small (optional) footprint in the RepositoryInfo/capabilities structure.

Additions to Schema:

The optional capabilities list in the repository info will contain an additional field. Shown here:

Metadata Capabilities:

capabilityTypeMutability(enumCapabilityTypeMutability)

Indicates the extent of the mutability of the metadata for the given repository. Note each level includes the capabilities of the previous/lower levels.

Levels of Mutable Metadata are:

  • none: (Default) Types (metadata) is read only. (same as CMIS 1.0)
  • createonly: Clients may create new types in addition to reading metadata. (i.e. deletes and updates to existing types are not permitted )
  • readwrite: Clients may perform all CRUD operations on the metadata for this repository. Create, Read, Update and Delete.
  • Note:Repository may place additional restrictions on these operations where necessary. These restrictions are repository specific. For example some repositories may not permit the deletion of a type if there are already instance documents of that type present. See ‘General constraints on metadata changes’ section below.

MetadataType Capabilities:

The repository should optionally be able to indicate the following: (specific structural details omitted for these until a later ‘official’ version of this doc)

1. A list of what property types are supported for creation. For example; a repository may only allow creating custom types with a subset of the complete list, like:cmis:propertyString and cmis:propertyInteger.

2. Alist (of enumeration choices) that would allow the repository to specify what Type attributes are settable for new types.

For example:

cmis:fileable,

cmis:queryable,

cmis:fulltextindexed,

cmis:controllablepolicy,

cmis:controllableACL

choiceLists

Additional Services to be added to Model

Repository Services would acquire the following methods:

  1. createType
  2. updatePropertyDefinitions
  3. deleteType
  4. deleteTypeTree

General constraints on metadata changes

Constraints on new type creation:

Generally when it comes to new properties on entirely new (leaf) types, there are no limits other than any limitations on properties that may be used and what type attributes may be set. These limitations will be enumerated in the capabilities list of the repository info as stated earlier.

Constraints on updating existing types:

These rules apply specifically to updatePropertyDefinitions when updating a type that is already present. All rules must not violate any rules that came earlier in the list. (e.g.When applying rule #8 you cannot violate rule #1 either) Note it is repository specific whether a given repository will permit any changes to types that already have instances present.

  1. Inherited properties MUST NOT be modified
  2. This includes constraints of any kind.
  3. CMIS spec defined properties MUST NOT be modified.
  4. This includes constraints of any kind.
  5. Only leaf types may be modified.
  6. i.e. If type already has child types defined then it (and all of its properties and constraints) MUST be considered read only.
  7. Any added properties marked as required MUST have a default value.
  8. Required properties MAY be changed to optional.
  9. Optional properties MUST NOT be changed to required.
  10. Properties MAY be removed.
  11. Property choice constraints MAY be changed in the following manner:
  12. ‘Open choice’MAY change from false to true.
  13. ‘Open choice’ MUST NOT change from true to false.
  14. Choices MAY be added or removed if ‘open choice’ is true.
  15. Choices MUST NOT be removed if ‘open choice’ is false
  16. Validation constraints (min/max length, min/max value) on existing properties MUST NOT be changed.

Permissions discussion:

TBD: Should we expose a new permission indicating whether the current user has rights to modify types (i.e. allowable actions on types) or just let the repository throw not authorized in cases where it is not permitted?

(Recommendation: throw exception)

Additional Services (Detail):

createType

Description: Creates a new type that is a subtype of an existing type. Only properties that are new to this type (not inherited) are passed to this method.

Inputs

Required:

  • ID repositoryId: The identifier for the Repository.
  • ObjectTypeId: The cmis:ObjectTypeId that will be assigned to this new type.
  • ParentObjectTypeId: The cmisObjectTypeId of the parent type.
  • <Array> newPropertyDefinitions: The property definitions that will be present on this new type. Note all types from the parent type are assumed to be inherited and should not be included in this array.
  • Note: The execution of this operation MUST not affect the definition of any other types or any other type’s current property definitions.
  • For example: Any properties on the type being created must not place constraints on other type’s properties when/if other properties ‘share’ property definitions.

Optional:

  • TBD: N/A
Outputs

ID objectId: The ID of the newly-created type if creation was successful.

Exceptions Thrown & Conditions
  • See section 2.2.1.4.1General Exceptions
  • TBD
updatePropertyDefinitions (or updateType)

Description: Updates propertyDefinitions for a speficied cmis:ObjectType.

Notes:

  • The execution of this operation MUST not affect the definition of any other types or any other type’s current property definitions.
  • For example: updatePropertyDefinitions can not be called on a type that already has child types since (by inheritance) changes to the parent type will affect the descendent types.
  • For example: Any properties on the type being modified must not place constraints on other type’s properties when other properties ‘share’ property definitions.
Inputs

Required:

  • ID repositoryId: The identifier for the Repository.
  • ObjectTypeId: The cmis:ObjectTypeId of the type to be modified.
  • <Array> propertyDefinitions: (new and updated properties) The property definitions that will be present on this type after the update is completed. This list should not include any inherited property definitions. Note all any non-inherited types that are not present in this list will be deleted from this type.
  • Note: Some repositories may not be able to perform deletion of individual propertyDefinitions from a type if there are instances of that type with that property populated. Other repositories may trim the instance data to match the new type. These behaviors are repository specific and not to be dictated by the spec. (discuss?) In the future these may be described as additional capabilities.
  • Optional: TBD
  • String changeToken: See section 2.2.1.3Change Tokens.
Outputs
  • ID objectId: The ID of the updated object.
  • String changeToken: See section 2.2.1.3Change Tokens.
Exceptions Thrown & Conditions
  • See section 2.2.1.4.1General Exceptions
  • TBD
deleteType

Description: Deletes the specified Type.

Inputs

Required:

  • ID repositoryId: The identifier for the Repository.
  • ObjectTypeId: The cmis:ObjectTypeId that will be deleted.

Optional:

  • Enum orphanedTypeInstances: An enumeration specifying how the repository MUST process instances of any orphaned objects whose type would no longer be defined. Valid values are:
  • delete: (Default) Delete the orphaned objects.
  • halt: Do not perform the operation and throw an exception.
Exceptions Thrown & Conditions
  • See section 2.2.1.4.1General Exceptions
  • TDB
deleteTypeTree

Description: Deletes the specified Type and all of its descendent types.

Notes:

  • Optional – I’m not certain that we need this. Can we get by with the much simpler single delete? Not sure if deleting trees of Types is something that we want to simplify. (discuss)
1.1.1.1.1Inputs

Required:

  • ID repositoryId: The identifier for the Repository.
  • ObjectTypeId: The cmis:ObjectTypeId that will be deleted along with all of its descendents.

Optional:

  • Enum orphanedTypeInstances: An enumeration specifying how the repository MUST process instances of any orphaned objects whose type would no longer be defined. Valid values are:
  • delete: (Default) Delete the orphaned objects.
  • halt: Do not perform the operation and throw an exception.
Outputs
  • <Array> ID failedToDelete: A list of identifiers of types that were not deleted.
Exceptions Thrown & Conditions
  • See section 2.2.1.4.1General Exceptions
  • updateConflict: See section 2.2.1.4.2Specific Exceptions.

REST examples of new functionality in use:

Example I – Creating a new type

POST to ‘Types Children’ URL to create the following type:

Type Description:

A new subclass of cmis:document. (Note this would be posted to the type children URL for cmis:document or whichever class was to be the parent for this new type)

Name/id : invoiceDocument

This class will be fileable, queryable, full text indexed and will have the following property definitions:

  1. (integer) FolderColor
  2. Constraints
  3. Required=true
  4. Choice values
  5. displayName=”green” value =1
  6. displayName=”gold” value =2
  7. displayName=”red” value =3
  8. displayName=”grey” value =4
  9. (string) AuditorName
  10. Constraints
  11. MaxLength = 64
  12. (booean) isApproved
  13. Constraints
  14. Default = ‘false
  15. (datetime) dateAudited

Note that none of these property definitions in the example are inherited.

Actual XML to POST

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<atom:entry xmlns:app=" xmlns:atom=" xmlns:cmisra=" xmlns:cmis=" xmlns:p8ext=" xmlns:cmism="

<cmisra:type xsi:type="cmis:cmisTypeDocumentDefinitionType" xmlns:xsi="

<cmis:id>invoiceDocument</cmis:id>

<cmis:localNamespace xsi:nil="true"/>

<cmis:displayName>Invoice Document</cmis:displayName>

<cmis:description>A single version of a document stored in an object store.</cmis:description>

<cmis:baseId>cmis:document</cmis:baseId>

<cmis:parentId>cmis:document</cmis:parentId>

<cmis:creatable>true</cmis:creatable>

<cmis:fileable>true</cmis:fileable>

<cmis:queryable>true</cmis:queryable>

<cmis:fulltextIndexed>true</cmis:fulltextIndexed>

<cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>

<cmis:controllablePolicy>false</cmis:controllablePolicy>

<cmis:controllableACL>false</cmis:controllableACL>

<cmis:propertyIntegerDefinition>

<cmis:id>FolderColor</cmis:id>

<cmis:displayName>FolderColor</cmis:displayName>

<cmis:description>Color of the invoice folder</cmis:description>

<cmis:propertyType>integer</cmis:propertyType>

<cmis:cardinality>multi</cmis:cardinality>

<cmis:updatability>readwrite</cmis:updatability>

<cmis:inherited>false</cmis:inherited>

<cmis:required>true</cmis:required>

<cmis:queryable>true</cmis:queryable>

<cmis:orderable>false</cmis:orderable>

<cmis:openChoice>false</cmis:openChoice>

<cmis:choice displayName="Green">

<cmis:value>1</cmis:value>

</cmis:choice>

<cmis:choice displayName="Gold">

<cmis:value>2</cmis:value>

</cmis:choice>

<cmis:choice displayName="Red">

<cmis:value>3</cmis:value>

</cmis:choice>

<cmis:choice displayName="Grey">

<cmis:value>4</cmis:value>

</cmis:choice>

<cmis:defaultValue>

<cmis:value>4</cmis:value>

</cmis:defaultValue>

</cmis:propertyIntegerDefinition>

<cmis:propertyStringDefinition>

<cmis:id>AuditorName</cmis:id>

<cmis:displayName>Auditor Name</cmis:displayName>

<cmis:description>The name of the Auditor for this invoice.</cmis:description>

<cmis:propertyType>string</cmis:propertyType>

<cmis:cardinality>single</cmis:cardinality>

<cmis:updatability>readwrite</cmis:updatability>

<cmis:inherited>false</cmis:inherited>

<cmis:required>false</cmis:required>

<cmis:queryable>true</cmis:queryable>

<cmis:orderable>true</cmis:orderable>

<cmis:openChoice>false</cmis:openChoice>

<cmis:maxLength>64</cmis:maxLength>

</cmis:propertyStringDefinition>

<cmis:propertyBooleanDefinition>

<cmis:id>IsApproved</cmis:id>

<cmis:displayName>Is Approved</cmis:displayName>

<cmis:description>Indicates if the invoice is approved by the auditor.</cmis:description>

<cmis:propertyType>boolean</cmis:propertyType>

<cmis:cardinality>single</cmis:cardinality>

<cmis:updatability>readonly</cmis:updatability>

<cmis:inherited>false</cmis:inherited>

<cmis:required>false</cmis:required>

<cmis:queryable>true</cmis:queryable>

<cmis:orderable>true</cmis:orderable>

<cmis:openChoice>false</cmis:openChoice>

<cmis:defaultValue>

<cmis:value>false</cmis:value>

</cmis:defaultValue>

</cmis:propertyBooleanDefinition>

<cmis:propertyDateTimeDefinition>

<cmis:id>DateAudited</cmis:id>

<cmis:displayName>DateAudited</cmis:displayName>

<cmis:description>The date and time this object was audited.</cmis:description>

<cmis:propertyType>datetime</cmis:propertyType>

<cmis:cardinality>single</cmis:cardinality>

<cmis:updatability>readwrite</cmis:updatability>

<cmis:inherited>false</cmis:inherited>

<cmis:required>false</cmis:required>

<cmis:queryable>true</cmis:queryable>

<cmis:orderable>true</cmis:orderable>

<cmis:openChoice>false</cmis:openChoice>

</cmis:propertyDateTimeDefinition>

<cmis:versionable>true</cmis:versionable>

<cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>

</cmisra:type>

</atom:entry>

Example II – Modifying the type created in example I

PUT to self URL for type returned from example I.

This put will delete the AuditorName, isApproved and dateAudited properties leaving only the FolderColor property on the invoiceDocument.

This class will be fileable, queryable, full text indexed and will have the following property definitions:

(integer) FolderColor

  1. Constraints
  2. Required=true
  3. Choice values
  4. displayName=”green” value =1
  5. displayName=”gold” value =2
  6. displayName=”red” value =3
  7. displayName=”grey” value =4

Notes. If there were instances of invoiceDocument that had already been created then this operation may either fail, or trim the instances such that that instances of invoiceDocument will conform to this new definition. It is repository specific as to which may occur.

Example XML for PUT (update)

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<atom:entry xmlns:app=" xmlns:atom=" xmlns:cmisra=" xmlns:cmis=" xmlns:p8ext=" xmlns:cmism="

<cmisra:type xsi:type="cmis:cmisTypeDocumentDefinitionType" xmlns:xsi="

<cmis:id>invoiceDocument</cmis:id>

<cmis:localNamespace xsi:nil="true"/>

<cmis:displayName>Invoice Document</cmis:displayName>

<cmis:description>A single version of a document stored in an object store.</cmis:description>

<cmis:baseId>cmis:document</cmis:baseId>

<cmis:parentId>cmis:document</cmis:parentId>

<cmis:creatable>true</cmis:creatable>

<cmis:fileable>true</cmis:fileable>

<cmis:queryable>true</cmis:queryable>

<cmis:fulltextIndexed>true</cmis:fulltextIndexed>

<cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>

<cmis:controllablePolicy>false</cmis:controllablePolicy>

<cmis:controllableACL>false</cmis:controllableACL>

<cmis:propertyIntegerDefinition>

<cmis:id>FolderColor</cmis:id>

<cmis:displayName>FolderColor</cmis:displayName>

<cmis:description>Color of the invoice folder</cmis:description>

<cmis:propertyType>integer</cmis:propertyType>

<cmis:cardinality>multi</cmis:cardinality>

<cmis:updatability>readwrite</cmis:updatability>

<cmis:inherited>false</cmis:inherited>

<cmis:required>true</cmis:required>

<cmis:queryable>true</cmis:queryable>

<cmis:orderable>false</cmis:orderable>

<cmis:openChoice>false</cmis:openChoice>

<cmis:choice displayName="Green">

<cmis:value>1</cmis:value>

</cmis:choice>

<cmis:choice displayName="Gold">

<cmis:value>2</cmis:value>

</cmis:choice>

<cmis:choice displayName="Red">

<cmis:value>3</cmis:value>

</cmis:choice>

<cmis:choice displayName="Grey">

<cmis:value>4</cmis:value>

</cmis:choice>

<cmis:defaultValue>

<cmis:value>4</cmis:value>

</cmis:defaultValue>

</cmis:propertyIntegerDefinition>

<cmis:versionable>true</cmis:versionable>

<cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>

</cmisra:type>

</atom:entry>