CMIS

Content:

  1. Introduction
  2. Concept
  3. Explore
  4. CRUD
  5. Query
  6. Versions
  7. Comparison with JCR and PHPCR

Introduction:

CMIS (Content Management Interoperability Services) is a standard for web service API to CMS/WCM/DMS/ECM (Content Management System / Web Content Management / Document Management System / Enterprise Content Management).

The standard is managed by OASIS. Version 1.0 was released in 2010 and version 1.1 was released in 2012.

CMIS supports 3 protocols:

CMIS is supported by a large number of CMS/WCM/DMS/ECM including:

CMIS client libraries are available for many programming languages including:

Concept:

CMIS data model is very simple.

Basically it just consists of:

folder
container for folders and documents
document
an artifact

In other words a virtual file system.

CMIS virtual file system

Explore:

Let us first try and explore a CMIS repository.

Java examples will use Apache Chemistry client library.

package cmisdemo;

import java.util.HashMap;
import java.util.Map;

import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.Property;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.enums.BindingType;

public class Explore {
    private static void list(String indent, Folder dir, boolean recurse, boolean showprops) {
        for(CmisObject item : dir.getChildren()) {
            System.out.printf("%s%s (%s)\n", indent, item.getName(), item.getType().getLocalName());
            if(showprops) {
                for(Property<?> p : item.getProperties()) {
                    if(p.getValue() != null) {
                        System.out.printf("%s- %s = %s\n", indent, p.getLocalName(), p.getValue());
                    }
                }
            }
            if(recurse && item instanceof Folder) {
                list(indent + "    ", (Folder)item, recurse, showprops);
            }
        }
    }
    public static void test(Map<String, String> param,  boolean recurse, boolean showprops) {
        System.out.println(param);
        Session ses = SessionFactoryImpl.newInstance().createSession(param);
        // server info
        System.out.println(ses.getRepositoryInfo().getName());
        System.out.println(ses.getRepositoryInfo().getDescription());
        System.out.println(ses.getRepositoryInfo().getProductName());
        System.out.println(ses.getRepositoryInfo().getProductVersion());
        // list items
        list("", ses.getRootFolder(), recurse, showprops);
    }
    public static void main(String[] args) {
        // Chemistry - AtomPub
        Map<String, String> chemistry_atompub = new HashMap<String, String>();
        chemistry_atompub.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        chemistry_atompub.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/chemistry/atom");
        chemistry_atompub.put(SessionParameter.REPOSITORY_ID, "test");
        chemistry_atompub.put(SessionParameter.USER, "test");
        chemistry_atompub.put(SessionParameter.PASSWORD, "test");
        test(chemistry_atompub, true, true);
        // Chemistry - SOAP
        Map<String, String> chemistry_soap = new HashMap<String, String>();
        chemistry_soap.put(SessionParameter.BINDING_TYPE, BindingType.WEBSERVICES.value());
        chemistry_soap.put(SessionParameter.WEBSERVICES_ACL_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_DISCOVERY_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_MULTIFILING_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_NAVIGATION_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_OBJECT_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_POLICY_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_REPOSITORY_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.WEBSERVICES_VERSIONING_SERVICE, "http://localhost:8080/chemistry/services/cmis?wsdl");
        chemistry_soap.put(SessionParameter.REPOSITORY_ID, "test");
        chemistry_soap.put(SessionParameter.USER, "test");
        chemistry_soap.put(SessionParameter.PASSWORD, "test");
        test(chemistry_soap, true, true);
        // OpenCMS - AtomPub
        Map<String, String> opencms_atompub = new HashMap<String, String>();
        opencms_atompub.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        opencms_atompub.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/opencms/cmisatom");
        opencms_atompub.put(SessionParameter.REPOSITORY_ID, "cmis-online");
        opencms_atompub.put(SessionParameter.USER, "Admin");
        opencms_atompub.put(SessionParameter.PASSWORD, "admin");
        test(opencms_atompub, false, false);
        // OpenCMS - SOAP
        Map<String, String> opencms_soap = new HashMap<String, String>();
        opencms_soap.put(SessionParameter.BINDING_TYPE, BindingType.WEBSERVICES.value());
        opencms_soap.put(SessionParameter.WEBSERVICES_ACL_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_DISCOVERY_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_MULTIFILING_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_NAVIGATION_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_OBJECT_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_POLICY_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_RELATIONSHIP_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_REPOSITORY_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.WEBSERVICES_VERSIONING_SERVICE, "http://localhost:8080/opencms/services/cmis?wsdl");
        opencms_soap.put(SessionParameter.REPOSITORY_ID, "cmis-online");
        opencms_soap.put(SessionParameter.USER, "Admin");
        opencms_soap.put(SessionParameter.PASSWORD, "admin");
        test(opencms_soap, false, false);
    }
}

Several CMIS client libraries exists for .NET including:

Examples will use DotCMIS.

using System;
using System.Collections.Generic;

using DotCMIS;
using DotCMIS.Client;
using DotCMIS.Client.Impl;

namespace CMISDemo.Explore
{
    public class Program
    {
        private static void List(string indent, IFolder dir, bool recurse, bool showprops)
        {
            foreach(ICmisObject item in dir.GetChildren()) {
                Console.WriteLine("{0}{1} ({2})", indent, item.Name, item.ObjectType.LocalName);
                if(showprops)
                {
                    foreach(IProperty p in item.Properties)
                    {
                        if(p.Value != null)
                        {
                            Console.WriteLine("{0}- {1} = {2}", indent, p.LocalName, p.Value);
                        }
                    }
                }
                if(recurse && item is IFolder)
                {
                    List(indent + "    ", (IFolder)item, recurse, showprops);
                }
            }
        }
        public static void Test(IDictionary<string, string> param, bool recurse, bool showprops)
        {
            Console.WriteLine(param);
            ISession ses = SessionFactory.NewInstance().CreateSession(param);
            // server info
            Console.WriteLine(ses.RepositoryInfo.Name);
            Console.WriteLine(ses.RepositoryInfo.Description);
            Console.WriteLine(ses.RepositoryInfo.ProductName);
            Console.WriteLine(ses.RepositoryInfo.ProductVersion);
            // list items
            List("", ses.GetRootFolder(), recurse, showprops);
        }
        public static void Main(string[] args)
        {
            // Chemistry - AtomPub
            IDictionary<string, string> chemistry_atompub = new Dictionary<string, string>();
            chemistry_atompub[SessionParameter.BindingType] = BindingType.AtomPub;
            chemistry_atompub[SessionParameter.AtomPubUrl] = "http://localhost:8080/chemistry/atom";
            chemistry_atompub[SessionParameter.RepositoryId] = "test";
            chemistry_atompub[SessionParameter.User] = "test";
            chemistry_atompub[SessionParameter.Password] = "test";
            Test(chemistry_atompub, true, true);
            // Chemistry - SOAP
            IDictionary<string, string> chemistry_soap = new Dictionary<string, string>();
            chemistry_soap[SessionParameter.BindingType] = BindingType.WebServices;
            chemistry_soap[SessionParameter.WebServicesAclService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesDiscoveryService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesMultifilingService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesNavigationService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesObjectService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesPolicyService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesRelationshipService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesRepositoryService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.WebServicesVersioningService] = "http://localhost:8080/chemistry/services/cmis?wsdl";
            chemistry_soap[SessionParameter.RepositoryId] = "test";
            chemistry_soap[SessionParameter.User] = "test";
            chemistry_soap[SessionParameter.Password] = "test";
            Test(chemistry_soap, true, true);
            // OpenCMS - AtomPub
            IDictionary<string, string> opencms_atompub = new Dictionary<string, string>();
            opencms_atompub[SessionParameter.BindingType] = BindingType.AtomPub;
            opencms_atompub[SessionParameter.AtomPubUrl] = "http://localhost:8080/opencms/cmisatom";
            opencms_atompub[SessionParameter.RepositoryId] = "cmis-online";
            opencms_atompub[SessionParameter.User] = "Admin";
            opencms_atompub[SessionParameter.Password] = "admin";
            Test(opencms_atompub, false, false);
            // OpenCMS - SOAP
            IDictionary<string, string> opencms_soap = new Dictionary<string, string>();
            opencms_soap[SessionParameter.BindingType] = BindingType.WebServices;
            opencms_soap[SessionParameter.WebServicesAclService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesDiscoveryService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesMultifilingService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesNavigationService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesObjectService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesPolicyService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesRelationshipService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesRepositoryService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.WebServicesVersioningService] = "http://localhost:8080/opencms/services/cmis?wsdl";
            opencms_soap[SessionParameter.RepositoryId] = "cmis-online";
            opencms_soap[SessionParameter.User] = "Admin";
            opencms_soap[SessionParameter.Password] = "admin";
            Test(opencms_soap, false, false);
            //
            Console.ReadKey();
        }
    }
}

libcmis and libcmis3 modules are available via pypi.

There seems to be some problems with Python 3 and libcmis3.

from cmislib.model import CmisClient

def list(indent, dir, recurse, showprops):
    for item in dir.getChildren():
        typ = item.getProperties()['cmis:objectTypeId'][5:]
        print('%s%s (%s)' % (indent, item.name, typ))
        if showprops:
            props = item.getProperties()
            for p in props:
                print('%s- %s = %s' % (indent, p, props[p]))
        if recurse and typ == 'folder':
            list(indent + '  ', item, recurse, showprops)

def test(url, usr, pwd, reponam, recurse, showprops):
    client = CmisClient(url, usr, pwd)
    repo = client.getRepository(reponam)
    repo._cmisClient = client # hack to work around a known bug
    print(repo.getRepositoryInfo()['repositoryName'])
    print(repo.getRepositoryInfo()['repositoryDescription'])
    print(repo.getRepositoryInfo()['productName'])
    print(repo.getRepositoryInfo()['productVersion'])
    list('', repo.getRootFolder(), recurse, showprops)

test('http://localhost:8080/chemistry/atom', 'test', 'test', 'test', True,True)
test('http://localhost:8080/opencms/cmisatom', 'Admin', 'admin', 'cmis-online', False, False)

Several CMIS client libraries exists for PHP including:

The examples will use Apache Chemistry client.

For production usage I would look at one of the alternatives.

<?php
include 'cmis_service.php';

function listf($indent, $client, $id, $recurse, $showprops) {
    foreach($client->getChildren($id)->objectList as $item) {
        $typ = substr($item->properties['cmis:objectTypeId'], 5);
        echo sprintf("%s%s (%s)\r\n", $indent, $item->properties['cmis:name'], $typ);
        if($showprops) {
            $props = $item->properties;
            foreach($props as $pk => $pv) {
                echo sprintf("%s- %s = %s\r\n", $indent, $pk, $pv);
            }
        }
        if($recurse && $typ == 'folder') {
            listf($indent . '  ', $client, $item->properties['cmis:objectId'], $recurse, $showprops);
        }
    }
}

function test($url, $usr, $pwd, $reponam, $recurse, $showprops) {
    $client = new CMISService($url, $usr, $pwd);
    echo $client->getRepositoryInfo()->repositoryInfo['cmis:repositoryName'] . "\r\n";
    echo $client->getRepositoryInfo()->repositoryInfo['cmis:repositoryDescription'] . "\r\n";
    echo $client->getRepositoryInfo()->repositoryInfo['cmis:productName'] . "\r\n";
    echo $client->getRepositoryInfo()->repositoryInfo['cmis:productVersion'] . "\r\n";
    listf('', $client, $client->getObjectByPath('/')->id, $recurse, $showprops);
}

test('http://localhost:8080/chemistry/atom', 'test', 'test', 'test', true, true);
test('http://localhost:8080/opencms/cmisatom', 'Admin', 'admin', 'cmis-online', false, false)
?>

CRUD:

Now let us do some basic CRUD operations.

Java examples will use Apache Chemistry client library.

package cmisdemo;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.Property;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.enums.BindingType;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;

// Note: paths are actually implementation specific but /cmis:name/cmis:name/cmis:name is common
public class CRUD {
    private static void dump(Session ses, String path) throws IOException {
        try {
            Document f = (Document) ses.getObjectByPath(path);
            for(Property<?> p : f.getProperties()) {
                if(p.getValue() != null) {
                    System.out.printf("%s = %s\n", p.getLocalName(), p.getValue());
                }
            }
            ContentStream stm = f.getContentStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(stm.getStream()));
            String line;
            while((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
        } catch (CmisObjectNotFoundException ex) {
            System.out.println(path + " does not exist");
        }
    }
    public static void main(String[] args) throws Exception {
        Map<String, String> param = new HashMap<String, String>();
        param.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
        param.put(SessionParameter.ATOMPUB_URL, "http://localhost:8080/chemistry/atom");
        param.put(SessionParameter.REPOSITORY_ID, "test");
        param.put(SessionParameter.USER, "test");
        param.put(SessionParameter.PASSWORD, "test");
        Session ses = SessionFactoryImpl.newInstance().createSession(param);
        // read
        dump(ses, "/RW/demo.txt");
        // create
        String s = "A\r\nBB\r\nCCC\r\n";
        Folder dir = (Folder) ses.getObjectByPath("/RW");
        Map<String, Object> props = new HashMap<String, Object>();
        props.put(PropertyIds.NAME, "demo.txt");
        props.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
        ContentStream stm = ses.getObjectFactory().createContentStream("demo.txt", s.length(), "text/plain", new ByteArrayInputStream(s.getBytes()));
        try {
            dir.createDocument(props, stm, VersioningState.NONE);
        } catch(CmisNameConstraintViolationException ex) {
            System.out.println("demo.txt did already exist");
        }
        // read
        dump(ses, "/RW/demo.txt");
        // delete
        ses.getObjectByPath("/RW/demo.txt").delete(true);
        // read
        dump(ses, "/RW/demo.txt");
    }
}

Several CMIS client libraries exists for .NET including:

Examples will use DotCMIS.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using DotCMIS;
using DotCMIS.Client;
using DotCMIS.Client.Impl;
using DotCMIS.Data;
using DotCMIS.Enums;
using DotCMIS.Exceptions;

namespace CMISDemo.CRUD
{
    public class Program
    {
        private static void Dump(ISession ses, string path)
        {
            try
            {
                Document f = (Document) ses.GetObjectByPath(path);
                foreach(Property p in f.Properties)
                {
                    if(p.Value != null)
                    {
                        Console.WriteLine("{0} = {1}", p.LocalName, p.Value);
                    }
                }
                IContentStream stm = f.GetContentStream();
                StreamReader sr = new StreamReader(stm.Stream);
                string line;
                while((line = sr.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
                sr.Close();
            }
            catch (CmisObjectNotFoundException)
            {
                Console.WriteLine(path + " does not exist");
            }
        }
        public static void Main(string[] args)
        {
        IDictionary<string, string> param = new Dictionary<string, string>();
        param[SessionParameter.BindingType] = BindingType.AtomPub;
        param[SessionParameter.AtomPubUrl] = "http://localhost:8080/chemistry/atom";
        param[SessionParameter.RepositoryId] = "test";
        param[SessionParameter.User] = "test";
        param[SessionParameter.Password] = "test";
        ISession ses = SessionFactory.NewInstance().CreateSession(param);
        // read
        Dump(ses, "/RW/demo.txt");
        // create
        string s = "A\r\nBB\r\nCCC\r\n";
        Folder dir = (Folder) ses.GetObjectByPath("/RW");
        IDictionary<String, Object> props = new Dictionary<String, Object>();
        props[PropertyIds.Name] = "demo.txt";
        props[PropertyIds.ObjectTypeId] = "cmis:document";
        IContentStream stm = ses.ObjectFactory.CreateContentStream("demo.txt", s.Length, "text/plain", new MemoryStream(Encoding.Default.GetBytes(s)));
        try
        {
            dir.CreateDocument(props, stm, VersioningState.None);
        }
        catch(CmisNameConstraintViolationException)
        {
            Console.WriteLine("demo.txt did already exist");
        }
        // read
        Dump(ses, "/RW/demo.txt");
        // delete
        ses.GetObjectByPath("/RW/demo.txt").Delete(true);
        // read
        Dump(ses, "/RW/demo.txt");
        //
            Console.ReadKey();
        }
    }
}

libcmis and libcmis3 modules are available via pypi.

There seems to be some problems with Python 3 and libcmis3.

from cmislib.model import CmisClient
from cmislib.exceptions import ObjectNotFoundException
from cmislib.exceptions import NameConstraintViolationException

def dump(repo, path):
    try:
        f = repo.getObjectByPath(path)
        props = f.getProperties()
        for p in props:
            print('%s = %s' % (p, props[p]))
        stm = f.getContentStream()
        print(stm.read())
        stm.close()
    except ObjectNotFoundException:
        print(path + ' does not exist')

client = CmisClient('http://localhost:8080/chemistry/atom', 'test', 'test')
repo = client.getRepository('test')
repo._cmisClient = client # hack to work around a known bug
# read
dump(repo, '/RW/demo.txt')
# create
s = 'A\r\nBB\r\nCCC\r\n'
dir = repo.getObjectByPath('/RW');
try:
    dir.createDocumentFromString('demo.txt', contentType='text/plain', contentString=s) # broken i Python 3.x and cmslib3
except NameConstraintViolationException:
    print('demo.txt did already exist')
# read
dump(repo, '/RW/demo.txt');
# delete
repo.getObjectByPath('/RW/demo.txt').delete()
# read
dump(repo, '/RW/demo.txt')

Several CMIS client libraries exists for PHP including:

The examples will use Apache Chemistry client.

For production usage I would look at one of the alternatives.

<?php
include 'cmis_service.php';

function dump($client, $path) {
    try {
        $f = $client->getObjectByPath($path);
        $props = $f->properties;
        foreach($props as $pk => $pv) {
            echo sprintf("%s = %s\r\n", $pk, $pv);
        }
    } catch(CmisObjectNotFoundException $ex) {
        echo "$path does not exist\r\n";
    }
}

$client = new CMISService('http://localhost:8080/chemistry/atom', 'test', 'test');
// read
dump($client, "/RW/demo.txt");
// create
$s = "A\r\nBB\r\nCCC\r\n";
$dir = $client->getObjectByPath("/RW");
try {
    $client->createDocument($dir->properties['cmis:objectId'], 'demo.txt', array(), $s, 'text/plain');
} catch(CmisConstraintException $ex) {
    echo "demo.txt did already exist\r\n";
}
// read
dump($client, "/RW/demo.txt");
// delete
$client->deleteObject($client->getObjectByPath("/RW/demo.txt")->properties['cmis:objectId']);
// read
dump($client, "/RW/demo.txt");
?>

Query:

CMIS defines a query language that allows SQL like queries:

Not all CMIS servers has implemented queries, so do not assume queries will work.

Versions:

CMIS also supports versions, so it has operations:

Again be careful to check the versioning capabilities of your specific CMIS server before assuming all functionality is available.

Comparison with JCR and PHPCR:

JCR (Java Content Repository) and PHPCR (PHP Content Repository) provide somewhat similar functionality to CMIS.

The differences include:

CMIS JCR/PHPCR
protocol API
always remote access (HTTP) remote access (any network protocol) or local access (call)
both application-repository and repository-repository only application-repository
high level low level
intended for full documents intended for small fragments
CMIS vs *CR

Article history:

Version Date Description
1.0 April 11th 2021 Initial version

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj