You are on page 1of 46

and

Florian Mller, Software Architect


Agenda

A quick CMIS tour

Introduction to Apache Chemistry

OpenCMIS demos

Outlook: CMIS, Apache Chemistry and Alfresco

Tech Talk: Alfresco CMIS


Online webinar, Wednesday, 3 August 2011
Content Management Interoperability Services
consumer

Client

read write

Services
Domain Model
provider

Vendor Mapping

CMIS lets you read, search, write, update,


Content
delete, version, control,
Repository content and metadata!
CMIS Use Cases

Content
Client Client
Repository

Content Content Content


Content
Repository Repository Repository
Content
Repository
Repository

Collaborative Content Creation


Portals
Client Application Integration
Mashup
CMIS Base Types


Document Folder
Content Container
Renditions Hierarchy
Version History Filing

Described by
Type Definitions

Relationship Policy
Source Object Target Object
Target Object
Type Definitions

Object Property
Type Id Property Id
Parent Display Name
Display Name
* Type
Queryable Required
Controllable Default Value

Document Folder Relationship Policy


Versionable Source Types
Allow Content Target Types

Custom Type
Base Properties

All objects Documents


String! cmis:name! Boolean! cmis:isImmutable!
ID! cmis:objectId! Boolean! cmis:isLatestVersion!
ID! cmis:baseTypeId! Boolean! cmis:isMajorVersion!
ID! cmis:objectTypeId! Boolean! cmis:isLatestMajorVersion!
String! cmis:createdBy! String! cmis:versionLabel!
DateTime! cmis:creationDate! ID! cmis:versionSeriesId!
String! cmis:lastModifiedBy! Boolean! cmis:isVersionSeriesCheckedOut!
DateTime! cmis:lastModificationDate! String! cmis:versionSeriesCheckedOutBy!
String! cmis:changetoken! ID! cmis:versionSeriesCheckedOutId!
String! cmis:checkinComment!
Folders Integer! cmis:contentStreamLength!
ID! cmis:parentId! String! cmis:contentStreamMimeType!
String! cmis:path! String! cmis:contentStreamFileName!
ID (multi)! cmis:allowedChildObjectTypeIds! ID! cmis:contentStreamId!

Relationships Policies
ID! cmis:sourceId! String! cmis:policyText!
ID! cmis:targetId!
Content Streams

Document * Rendition
Mime Type Kind
Length Mime Type

Content Stream
Stream Id

* Maximum length is repository specific


Access Control

ACL
Object
ACE
Principal
Permissions
Direct

Permissions
cmis:read
cmis:write
cmis:all
<repository specific>
Document Versioning

Document
Repository Vendor May Support
V1 Version Specific Folder Filing
Minor Query All Versions
Create Minor, Major, PWCs
Version Series

V2 checkout
Major

PWC

V3
checkin
Major
Policies

Repository specific Policies

Retention Security

Client
ly
app

Document

* Note: Optional Capability


Change Log

Change Events

Repo Create Update Delete Client


logs discover

Change Event:
Object Id
Change Time
Change Type created, updated, deleted, security
Properties for updated events

* Note: Optional Capability


CMIS Query Language

SELECT and FROM clauses


o Identify which properties from which types to return

WHERE clause
o Restrict returned rows to those that meet all constraints
o Predicates: comparison, in, like, null, any, is null
o Function Predicates: contains(), in_folder(), in_tree()
o Operators: and, or, not

ORDER BY clause
o Order results by one or more columns

Each Type is projected as a Table


Do You Understand These Queries?

SELECT cmis:name
FROM cmis:document
WHERE contains('alfresco')

SELECT cmis:name, cmis:lastModificationDate


FROM cmis:document
WHERE cmis:lastModifiedBy = 'admin'
ORDER BY cmis:lastModificationDate DESC

SELECT cmis:name, cmis:contentStreamLength


FROM cmis:document
WHERE IN_TREE('<folderObjectId>')
AND cmis:contentStreamLength > 100000
ORDER BY cmis:contentStreamLength
CMIS Services

Browse Inspect Act

Repository Object Object


- Get Server Information - Read Content - Write Content
- Get Type Definitions - Get Properties - Set Properties
- Get ACLs - Create Folder / Doc /
- Get Allowable Actions Relation
- Delete
- Move
- Set ACLs
Navigation Versioning
- Walk Folder / Doc - Walk Version History
Hierarchy
- Get Checked-out
Versioning
- Check-out / In
Relationship - Cancel Check-out
- Traverse Relationship(s) - Delete Version(s)

Discovery
- Issue Query
- Get Change Log Policy Policy
- Get Applied Policies - Apply / Remove
CMIS Cheat Sheet

http://cmis.alfresco.com/cmis-cheatsheet.pdf
CMIS Bindings

CMIS 1.0 defines two bindings:


o AtomPub binding
o Web Services binding

CMIS 1.1 will add a new binding:


o Browser binding (JSON)

Dont bother
There are Open Source libraries for that
Apache Chemistry
TM

Open Source implementations of

Apache Chemistry is the umbrella project for all CMIS


related projects within the Apache Software Foundation.

Apache Chemistry provides libraries and frameworks for


Java, Python, PHP and .NET.

Website: http://chemistry.apache.org
Main Objective

Developers should focus on the CMIS domain model!

Decreased learning curve: Developers can learn just


the CMIS domain model and ignore the transport details
of all the binding implementations.

Rapid start. From download to listing the first folder in


minutes.

Be compliant. Chemistry libraries have been tested


against many, many repositories.
Apache Chemistry

Application

Libraries Apache Chemistry


(ORM, connection pools, etc.)

ODBC / JDBC CMIS Bindings

CMIS Domain
SQL
Model

Relational DB Content Repository


Subprojects

OpenCMIS (Java, server and client)


o very mature
o well tested against all major servers

cmislib (Python, client)


o mature
o well tested against most major servers

phpclient (PHP, client)


o basic specification coverage
o used in a few production systems

DotCMIS (.NET, client)


o an OpenCMIS port (same architecture, similar API)
o works against all tested servers but needs more testing
History

May 2009: Started as an incubator project by


Nuxeo and Day (now Adobe)

February 2010: Metaversant contributed cmislib

February 2010: Alfresco, OpenText and SAP contributed


OpenCMIS

May 2010: Alfresco contributed phpclient

January 2011: Alfresco contributed DotCMIS

February 2011: Graduated to a top level project


OpenCMIS

OpenCMIS consists of a collection of Java libraries,


frameworks and tools:

Client library

Server framework

Two test repositories (InMemory and FileShare)

CMIS Browser (web application, AtomPub only)

CMIS Workbench (desktop application for developers)

FIT and TCK


Get hold of OpenCMIS

OpenCMIS is available

as source code:
https://svn.apache.org/repos/asf/chemistry/opencmis/trunk/

as release package with all dependencies:


http://chemistry.apache.org/java/download.html

via Maven:
http://chemistry.apache.org/java/developing/dev-use-with-maven.html

Last released version is 0.4.0


OpenCMIS Architecture
OpenCMIS Client Library

Client API
o OO API
You want this API!
o Easy to use
o Build-in caching

Client Binding API


o Low-level
o Very close to the CMIS specification
o More control, less comfort
OpenCMIS Client Interfaces
loads

ObjectId

0..n
RepositoryInfo Rendition AllowableActions ACL PropertyData

0..n 0..n
0..n loads
ACE

Repository QueryResult CmisObject Property


target 0..n
source

loads loads FileableCmisObject


creates

SessionFactory creates Session Folder Document Policy Relationship


0..n
0..n

0..n
loads

ContentStream

ChangeEvents

0..n FolderType DocumentType PolicyType RelationshipType

ChangeEvent

ObjectType PropertyDefinition
9..n

1 0..n
OpenCMIS Main Client Interfaces

AllowableActions ObjectId ACL

0..n
ACE

Rendition CmisObject Property


0..n 0..n

FileableCmisObject

Folder Document Policy Relationship

ContentStream
Aspects, Aspects, Aspects

CMIS 1.0 has no native support for aspects

Secondary types (= aspects) will be in CMIS 1.1

Alfresco provides read and write access to aspects and


aspect properties through CMIS extensions

Theoretically, every CMIS client can read and write


aspects but that is rather troublesome
Alfresco OpenCMIS Extension

The Alfresco OpenCMIS Extension transparently adds


aspect support to OpenCMIS

Hosted on Apache Extras (Google Code),


Apache license:
http://apache-extras.org/p/alfresco-opencmis-extension

See the project page for setup instructions.


Its really simple.
OpenCMIS Sessions

CMIS is stateless!

OpenCMIS introduces a session concept to support caching


o Its all about performance
o Reduce the number of calls to the repository

OpenCMIS caches:
o Repository infos
o Type definitions
o AtomPub links
o CMIS objects
Connect to a repository Variant 1

// set up session parameters


Map<String, String> parameter = new HashMap<String, String>();

parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
parameter.put(SessionParameter.ATOMPUB_URL,
"http://cmis.alfresco.com/service/cmis");
parameter.put(SessionParameter.REPOSITORY_ID,
"84ccfe80-b325-4d79-ab4d-080a4bdd045b");

parameter.put(SessionParameter.USER, "admin");
parameter.put(SessionParameter.PASSWORD, "admin");

// create the session


SessionFactory factory = SessionFactoryImpl.newInstance();
Session session = factory.createSession(parameter);
Connect to a repository Variant 2

// set up session parameters


Map<String, String> parameter = new HashMap<String, String>();

parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
parameter.put(SessionParameter.ATOMPUB_URL,
"http://cmis.alfresco.com/service/cmis");
parameter.put(SessionParameter.REPOSITORY_ID,
"84ccfe80-b325-4d79-ab4d-080a4bdd045b");

parameter.put(SessionParameter.USER, "admin");
parameter.put(SessionParameter.PASSWORD, "admin");

// get the list of repositories and choose the first one


SessionFactory factory = SessionFactoryImpl.newInstance();

List<Repository> repositories = factory.getRepositories(parameter);


Session session = repositories.get(0).createSession();
Using the Session

RepositoryInfo ri = session.getRepositoryInfo();
String id = ri.getId();
String name = ri.getName();

CmisObject object1 = session.getObject("1234567890");!


CmisObject object2 = session.getObjectByPath("/my/path/doc");!

Folder rootFolder = session.getRootFolder();!


String rootFolderId = rootFolder.getId();!
!
for(CmisObject object: rootFolder.getChildren()) {!
String name = object.getName();!

if(object instanceof Document) {!


Document doc = (Document) object;!
long size = doc.getContentStreamLength(); !
}!
}!
CMIS Workbench

Live samples with the CMIS Workbench



Navigation

import org.apache.chemistry.opencmis.commons.*;
import org.apache.chemistry.opencmis.commons.data.*;
import org.apache.chemistry.opencmis.commons.enums.*;
import org.apache.chemistry.opencmis.client.api.*;

// get root folder


Folder root = session.getRootFolder();
String rootFolderName = root.getName();

println "Root folder: ${rootFolderName}\n"

// print root folder children


for(CmisObject object: root.getChildren()) {

String name = object.getName();


String typeId = object.getType().getId();
String path = object.getPaths().get(0);

println "${name} \t${typeId} \t(${path})"

// get parents
/*
for(CmisObject parent: object.getParents()) {
String parentName = parent.getName();
println " Parent: ${parentName}"
}
*/
}
Paging

import org.apache.chemistry.opencmis.commons.*;!
import org.apache.chemistry.opencmis.commons.data.*;!
import org.apache.chemistry.opencmis.commons.enums.*;!
import org.apache.chemistry.opencmis.client.api.*;!
!
Folder root = session.getRootFolder();!
!
printList( root.getChildren() )!
!
//printList( root.getChildren().getPage(3) )!
!
//printList( root.getChildren().skipTo(2) )!
!
//printList( root.getChildren().skipTo(2).getPage(3) )!
!
!
!
void printList(ItemIterable<CmisObject> list) {!
list.each { println "${it.name} \t${it.type.id}" }!
!
long numItems = list.getTotalNumItems();!
boolean hasMore = list.getHasMoreItems();!
!
println "--------------------------------------"!
println "Total number: ${numItems}"!
println "Has more: ${hasMore}" !
println "--------------------------------------"!
}!
Properties

import org.apache.chemistry.opencmis.commons.*;
import org.apache.chemistry.opencmis.commons.data.*;
import org.apache.chemistry.opencmis.commons.enums.*;
import org.apache.chemistry.opencmis.client.api.*;

CmisObject object = session.getObjectByPath("/User Homes/florian/Test Folder/MyText");

for(Property<?> property: object.getProperties()) {

String propId = property.getId();


String displayName = property.getDefinition().getDisplayName();
String queryName = property.getDefinition().getQueryName();
PropertyType datatype = property.getType();
Object value = property.getFirstValue();

println "${displayName}: ${value}"


println " Data type: ${datatype}"
println " Id: ${propId}"
println " Query name: ${queryName}"
println ""
}
Content

import org.apache.chemistry.opencmis.commons.*;!
import org.apache.chemistry.opencmis.commons.data.*;!
import org.apache.chemistry.opencmis.commons.enums.*;!
import org.apache.chemistry.opencmis.client.api.*;!
!
CmisObject object = session.getObjectByPath("/User Homes/florian/Test Folder/MyText");!
!
if(!(object instanceof Document)) {!
throw new Exception("Not a document!");!
}!
!
Document doc = (Document) object;!
!
ContentStream content = doc.getContentStream();!
!
if(content == null) {!
throw new Exception("Document has no content!");!
}!
!
String filename = content.getFileName();!
String mimeType = content.getMimeType();!
long length = content.getLength();!
InputStream stream = content.getStream();!
!
println "File: ${filename}"!
println "MIME Type: ${mimeType}"!
println "Size: ${length} bytes"!
println "Has stream: " + (stream != null)!
!
Query

import org.apache.chemistry.opencmis.commons.*
import org.apache.chemistry.opencmis.commons.data.*
import org.apache.chemistry.opencmis.commons.enums.*
import org.apache.chemistry.opencmis.client.api.*

String cql = "SELECT cmis:objectId, cmis:name, cmis:contentStreamLength FROM cmis:document";

ItemIterable<QueryResult> results = session.query(cql, false);

//ItemIterable<QueryResult> results = session.query(cql, false).getPage(10);


//ItemIterable<QueryResult> results = session.query(cql, false).skipTo(10).getPage(10);

for(QueryResult hit: results) {


for(PropertyData<?> property: hit.getProperties()) {

String queryName = property.getQueryName();


Object value = property.getFirstValue();

println "${queryName}: ${value}"


}

println "--------------------------------------"
}
Folders

import org.apache.chemistry.opencmis.commons.*;!
import org.apache.chemistry.opencmis.commons.data.*;!
import org.apache.chemistry.opencmis.commons.enums.*;!
import org.apache.chemistry.opencmis.client.api.*;!
!
Folder root = session.getRootFolder();!
!
// create a new folder!
Map<String, Object> properties = new HashMap<String, Object>();!
properties.put("cmis:objectTypeId", "cmis:folder");!
properties.put("cmis:name", "a new folder");!
!
Folder newFolder = root.createFolder(properties);!
!
printProperties(newFolder);!
!
!
// update properties!
Map<String, Object> updateproperties = new HashMap<String, Object>();!
updateproperties.put("cmis:name", "renamed folder");!
!
newFolder.updateProperties(updateproperties);!
!
newFolder.refresh();!
printProperties(newFolder);!
!
!
// delete folder!
newFolder.deleteTree(true, UnfileObject.DELETE, true);!
!
Documents

import org.apache.chemistry.opencmis.commons.*;
import org.apache.chemistry.opencmis.commons.data.*;
import org.apache.chemistry.opencmis.commons.enums.*;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.*;
import org.apache.chemistry.opencmis.client.api.*;

Folder root = session.getRootFolder();

// create a new document


String name = "myNewDocument.txt";

Map<String, Object> properties = new HashMap<String, Object>();


properties.put("cmis:objectTypeId", "cmis:document");
properties.put("cmis:name", name);

byte[] content = "Hello World!".getBytes();


InputStream stream = new ByteArrayInputStream(content);
ContentStream contentStream = new ContentStreamImpl(name, content.length, "text/plain", stream);

Document newDoc = root.createDocument(properties, contentStream, VersioningState.MAJOR);

printProperties(newDoc);

// delete document
newDoc.delete(true);

void printProperties(CmisObject object) {


object.properties.each { println "${it.id}: ${it.firstValue}" }
println "--------------------------------------"
}
CMIS Outlook

The CMIS TC is working on CMIS 1.1

CMIS 1.1 adds new features


o Type mutability
o Browser Binding
o Secondary Types
o

Release date: 2012???

Will it be backwards compatible?


o We dont know yet.
o Apache Chemistry will hide binding changes.
Apache Chemistry Outlook

Tests and documentation


o Make sure it works with as many CMIS servers and
clients as possible
o Make the usage of Apache Chemistry as simple as possible

Apache Chemistry sandboxes


o Implementations of CMIS 1.1 features
o Feedback for the CMIS TC
Alfresco CMIS Outlook

Alfresco 4.x
o Switch to the OpenCMIS server framework
o Many improvements: speed, memory consumption, compliance
o OpenCMIS client libraries are embedded and available in Web Scripts
o Have a look: http://cmis.alfresco.com

Tech Talk: Alfresco CMIS


Online webinar, Wednesday, 3 August 2011
o Alfresco CMIS mapping
o CMIS changes in Alfresco 4.x
o CMIS 1.1 browser binding (JSON)
o Performance optimization
o Whatever you want to talk about
Questions

You might also like