As described in section 1.4.2 HTML forms are used to create, update and delete CMIS content.
The form submission method (HTML form attribute “method”) MUST be “POST”. The encoding type (HTML form attribute “enctype”) MUST be either "application/x-www-form-urlencoded" or "multipart/form-data" if no content stream is attached to the form. The encoding type MUST be “multipart/form-data” if a content stream is attached to the form data.
The names of the controls within the form are defined by the patterns in the following sections. All control names are case-insensitive as defined by the HTML specification. Control names MUST be unique within a form. If the control value of an optional parameter is set to an empty string (“”) the default value MUST be used.
A client MAY add controls to a form that are not defined by CMIS as long as the control names don’t conflict with the patterns described in this specification.
Since control values are strings, all other data types have to be serialized to strings.
The same rules that apply to the serialization to JSON apply here.
Action
An HTML form used to POST CMIS content MUST include a control named “cmisaction” that indicates the CMIS operation to be performed. See section 1.4.3 for valid control values. The value of the control is case insensitive.
Example:
Structured and Array Parameters
Some CMIS operations require structured parameters and arrays of values. Since HTML forms don’t support that usage, some CMIS operation parameters are split into multiple controls in a form.
For example, a CMIS property is split into a control that holds the property id and another control that hold property value. The association between the two controls is done by convention.
The entirety of all properties is made up of an array of these property controls.
Names of controls that are part of an array end with “[]” where is a positive integer. Arrays MUST always start with the index 0 and MUST be gapless.
Example:
An array of three properties looks like this in a HTML form:
If a client sends invalid, incomplete or inconsistent data the repository SHOULD return an invalidArgument error.
CMIS Controls
This section lists all HTML form controls used by CMIS operations.
ID’s
Object id:
Control name: “objectId”
Control value: Object id
Example:
Folder id:
Control name: “folderId”
Control value: Folder id
Example:
Source folder id:
Control name: “sourceFolderId”
Control value: Folder id
Example:
Target folder id:
Control name: “targetFolderId”
Control value: Folder id
Example:
Single-value Properties
A single-value property is made up of a pair of a “propertyId” control and a “propertyValue” control with the same
. To unset the property, the “propertyValue” control MUST NOT be present.
does not imply any order.
Property Id:
Control name: “propertyId[
]”
Control value: Property id
Property value:
Control name: “propertyValue[
]”
Control value: Property value
Example:
Multi-value Properties
A multi-value property is made up a “propertyId” control and a series of “propertyValue” controls with the same
. To unset the property, no “propertyValue” control MUST be present.
does not imply any order, but defines the order of the values.
Property Id:
Control name: “propertyId[
]”
Control value: Property id
Property values:
Control name: “propertyValue[
][]”
Control value: Property value at position
Example:
Access Control
Adding Access Control Entries (ACEs)
To add an ACE to a CMIS object, a control named “addACEPrincipal” control is used with an , with zero or more “addACEPermission” controls, each with the same and another subindex,
.
To remove an ACE from a CMIS object, a control named “removeACEPrincipal” is used with an , and zero or more “removeACEPermission” controls, each with the same and another subindex,
.
and
don’t imply any order.
Principal
Control name: “removeACEPrincipal[]”
Control value: Principal id
Permission
Control name: “removeACEPermission[][
]”
Control value: Permission id
Example:
ACL propagation
To specify how to propagate ACE’s, a control named “ACLPropagation” is used.
Control name: “ACLPropagation”
Control value: ACL propagation enum ("objectonly", "propagate", "repositorydetermined")
Example:
Policies
Policies are assigned to CMIS objects by including a control named “policy” with an index of
. A policy list is made up of a series of these “policy” controls.
does not imply any order.
Policy:
Control name: “policy[
]”
Control value: Policy id
Example:
Change Token
A CMIS change token is included by using a form control named “changeToken”. If the value of the control is set to the empty string, then the repository MUST treat the change token as not set.
When a document is checked in, a control named “versioningState” is used to set the versioning state and a control named “checkinComment” is used to include comments.
Versioning State:
Control name: “versioningState”
Control value: Versioning state enum ("none", "major", "minor", "checkedout")
Example:
Checkin Comment
Control name: “checkinComment”
Control value: Checkin comment
Example:
Query
A CMIS query can be constructed using a control named “statement” and set of controls to specify the query options.
Statement:
Control name: “statement”
Control value: CMIS query statement
Search all versions:
Control name: “searchAllVersions”
Control value: boolean (“true”, “false”)
Include relationships:
Control name: “includeRelationships”
Control value: includeRelationships enum ("none", "source" ,"target", "both")
Rendition filter:
Control name: “renditionFilter”
Control value: rendition filter
Include allowable actions:
Control name: “includeAllowableActions”
Control value: boolean (“true”, “false”)
Max items:
Control name: “maxItems”
Control value: non-negative integer
Skip count:
Control name: “skipCount”
Control value: non-negative integer
Example:
Content
A file select control SHOULD be used to attach content.
Control name: “content”
Control value: none
File:
Access to Form Response Content
JSON response content is subject to the same security constraints as any other kind of JavaScript which means that a browser will not allow JavaScript in a page to access JSON objects included in an HTML Form response if that response came from a different domain than the rest of the page content. For example, suppose a browser displayed an HTML Form from Web Server foo.example.com to create a document in a CMIS repository on server bar.example.com. When the user submits the form, there is no way for the page to access the JSON object representing the new document created as a response to the submitted form.
To make it possible for a browser client to access the JSON content answered from the CMIS repository, we introduce an optional token called “cmistransaction”. It is a client generated value that is intended to be used exactly once by the client to retrieve information about the results of a previous CMIS HTML Form post.
To make this work, the CMIS repository MUST keep the core result details (the status code, object id and error message) of a completed request and make those details available to the client in a later request.
In order to correlate the result of a CMIS request with the later call to retrieve the result of that request, the client needs to generate a unique string and include this in the submitted HTML form in a form control with the name “cmistransaction”. The mechanism to generate the value for this form control is a client decision and the only requirement on this mechanism is that it should be generated in a way that makes it unique enough that the client can retrieve the intended result, within a relatively short period of time (within about one hour). For example, one approach would generate the value by concatenating the number of milliseconds since 1970/01/01, UTC, with a random number and the name of the cmis object
Example:
type="hidden" value="0" />
After the operation has been performed, the client can retrieve the result by sending a HTTP GET requested to the repository URL (see section 1.3.1) with the selector set to “lastResult” and a parameter “cmistransaction” which is set to the same string previously sent with the form.
The result details MUST be answered as a JSON object containing these elements.
integer code
An integer containing the HTTP status code for the operation.
string objectId
A string containing the id of the object, if the operation was successful. If the operation was not successful, the value of this string is undefined.
string exception
A string containing the exception, if the operation was unsuccessful. If the operation was successful, the value of this string is undefined.
string message
A string containing the error message, if the operation was unsuccessful. If the operation was successful, the value of this string is undefined.
The result details SHOULD
only be available to the same client (as defined by the client’s IP address) that called the operation.
not be kept longer than an hour, since they are supposed to be retrieved immediately after the operation by the client.
only be retrievable once. That is, a second attempt SHOULD return an invalidArgument error (code = 0).
If the value of the parameter “cmistransaction” is invalid, the “code” field of this JSON object MUST be set to 0.
If the “cmistransaction” control is not specified in the form, the repository does not need to keep the result details because there is no way for the client to retrieve them.
Example:
When the client submits the HTML form, it can include a form control with the name “cmistransction” like this…
type="hidden" value="0" />
Soon thereafter, the client could retrieve the results of the form post by making a request like this
http://localhost:8080/opencmis/browser/A1?cmisselector=lastResult&clientToken=showNewDocumentId&cmistransaction=1296216073275-4312331-document
and then, the repository would answer a JSON object that contains the result details, like this …
{
code : 201,
objectId : "21983210980-2132-23 objectId",
exception : null,
message : null
}
Then the client could retrieve the details for the object using its objectId, as described in section 1.3.3.
Client Implementation Hints
Most applications don’t want to show the JSON object representations to the end-user after (s)he clicks the form submit button. After all, business users using web browsers don’t want to look at raw JSON content.
To avoid showing JSON to the user, the POST response can instead be directed to a hidden iframe. The iframe’s onLoad event can be used as an operation status notification. When it is triggered the operation is complete on the repository side and it is safe then to retrieve the results.
Server Implementation Hints
The use of transaction id’s can make CMIS stateful since the server has to remember details of a previous service request. However, the state can in fact be kept entirely on the client, to eliminate the need for the server to be stateful at all.
State on Server
Result details are non-permanent data and don’t need to be persisted. A simple in-memory store would be sufficient.
When a repository receives a “lastResult” request it should check the IP address of the client and the expiration time of the result details before it replies. This ensures that the data is not being retrieved by a malicious client, and that the requested data is relevant.
State on Client
The state can be managed on the client side using browser cookies, which keeps the repository stateless.
When a “cmistransaction” control is sent with the form data, the repository can attach a cookie to its POST response. The cookie name is derived from the “cmistransaction” value and the cookie value would contain the result details.
When the repository receives a “lastResult” request, it also receives the cookies from the browser. So, if the repository can find a cookie that matches the “cmistransaction” parameter value it can send back the cookie value and delete the cookie. If there is no corresponding cookie, it can reply with an error message.
Since the browser takes care of the cookie expiration and cookies can only be sent from the originating client, there are no new additional security and lifecycle issues for the repository to handle.
Browser Binding Examples
All of the examples used in this document were created using the Apache Chemistry project.
Getting Repository Info
Repository information is retrieved using an HTTP GET of the service document URL. The response is a JSON object containing properties each of which describes a single CMIS repository as a nested JSON object.
"repositoryDescription":"InMemory Test Repository",
"vendorName":"OpenCMIS",
"principalIdAnyone":"anyone"
}
}
Getting Folder Children
The content of a CMIS folder is obtained using an HTTP GET of an object URL for the folder. The response is a JSON object which contains properties such as hasMoreItems, numItems, as well as an array of JSON objects each of which describes a child object, such as a cmis:folder or a cmis:document.
In this example the objectId is used as the selector.
GET /A1/root?objectId=101 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: xxxx
{
"numItems":3,
"objects":[
{
"object":{
"properties":{
"cmis:lastModificationDate":{
"cardinality":"single",
"type":"datetime",
"displayName":"CMIS Last Modification Date Property",
"value":1298396347156,
"queryName":"cmis:lastModificationDate",
"localName":"cmis:lastModificationDate",
"id":"cmis:lastModificationDate"
},
"cmis:contentStreamFileName":{
"cardinality":"single",
"type":"string",
"displayName":"CMIS Content Stream File Name Property",
"value":"data.txt",
"queryName":"cmis:contentStreamFileName",
"localName":"cmis:contentStreamFileName",
"id":"cmis:contentStreamFileName"
},
"PickListProp":{
"cardinality":"single",
"type":"string",
"displayName":"Sample Pick List Property",
"value":"blue",
"queryName":"PickListProp",
"localName":"PickListProp",
"id":"PickListProp"
},
"cmis:baseTypeId":{
"cardinality":"single",
"type":"id",
"displayName":"CMIS Base Type Id Property",
"value":"cmis:document",
"queryName":"cmis:baseTypeId",
"localName":"cmis:baseTypeId",
"id":"cmis:baseTypeId"
},
"cmis:isImmutable":{
"cardinality":"single",
"type":"boolean",
"displayName":"CMIS Is Immutable Property",
"value":false,
"queryName":"cmis:isImmutable",
"localName":"cmis:isImmutable",
"id":"cmis:isImmutable"
},
"cmis:objectId":{
"cardinality":"single",
"type":"id",
"displayName":"CMIS Object Id Property",
"value":"114",
"queryName":"cmis:objectId",
"localName":"cmis:objectId",
"id":"cmis:objectId"
},
"cmis:createdBy":{
"cardinality":"single",
"type":"string",
"displayName":"CMIS Created By Property",
"value":"florian",
"queryName":"cmis:createdBy",
"localName":"cmis:createdBy",
"id":"cmis:createdBy"
},
"cmis:lastModifiedBy":{
"cardinality":"single",
"type":"string",
"displayName":"CMIS Last Modified By Property",
"value":"florian",
"queryName":"cmis:lastModifiedBy",
"localName":"cmis:lastModifiedBy",
"id":"cmis:lastModifiedBy"
},
"cmis:changeToken":{
"cardinality":"single",
"type":"string",
"displayName":"CMIS Change Token Property",
"value":"1298396347156",
"queryName":"cmis:changeToken",
"localName":"cmis:changeToken",
"id":"cmis:changeToken"
},
"cmis:creationDate":{
"cardinality":"single",
"type":"datetime",
"displayName":"CMIS Creation Date Property",
"value":1298396347156,
"queryName":"cmis:creationDate",
"localName":"cmis:creationDate",
"id":"cmis:creationDate"
},
"StringProp":{
"cardinality":"single",
"type":"string",
"displayName":"Sample String Property",
"value":"My Doc StringProperty 6",
"queryName":"StringProp",
"localName":"StringProp",
"id":"StringProp"
},
"cmis:contentStreamMimeType":{
"cardinality":"single",
"type":"string",
"displayName":"CMIS Content Stream Mime Type Property",
As described in Section 1.2.6, a client token can be passed into a CMIS read service request to simplify the handling of the returned JSON object. Here is an example of how that can be used in a getRepositorories request.
Suppose an HTTP GET of
http://www.example.com/cmis/getRepositories
answered a JSON response like this …
{"A1":
{
"repositoryDescription":"InMemory Test Repository",
"repositoryId":"A1",
"repositoryName":"InMemory Repository"
}
}
Note that the contents of the response are abbreviated for brevity.
Adding the clientToken parameter to the request like this
"repositoryDescription":"InMemory Test Repository",
"repositoryId":"A1",
"repositoryName":"InMemory Repository"
}
}
)
On the client side, the result is a call to the JavaScript function, showRepositoryInfo, with the JSON object passed as a parameter.
Putting it all together, the following illustration and sample code shows how a JSON object is fetched when an HTML page is loaded, and how the JSON object can be handled by a JavaScript function.
Repository Information
Creating a Document
A CMIS document can be created using HTTP POST of an HTML form to an