apache chemistry: the alfresco open source implementation of cmis

46
and Florian Müller, Software Architect

Upload: alfresco-software

Post on 08-May-2015

7.472 views

Category:

Technology


11 download

DESCRIPTION

Learn how to make CMIS simple for Java client and server developers. Apache Chemistry is the umbrella project for all CMIS (Content Management Interoperability Services) related projects within the Apache Software Foundation and OpenCMIS is a collection of Java libraries, frameworks and tools around CMIS specification.

TRANSCRIPT

and Florian Müller, 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

Client

Content Repository

Services

Domain Model

read write

co

nsu

me

r p

rovid

er

Vendor Mapping

CMIS lets you read, search, write, update, delete, version, control, … content and metadata!

CMIS Use Cases

Client

Content Repository

Content Repository

Content Repository Client

Content Repository Content

Repository Content Repository

•  Collaborative Content Creation •  Portals •  Client Application Integration •  Mashup

CMIS Base Types

   Document •  Content •  Renditions •  Version History

Folder •  Container •  Hierarchy •  Filing

Relationship •  Source Object •  Target Object

Policy •  Target Object

Described by Type Definitions

Type Definitions

*

Custom Type

Object •  Type Id •  Parent •  Display Name •  Queryable •  Controllable

Document •  Versionable •  Allow Content

Folder Relationship •  Source Types •  Target Types

Policy

Property •  Property Id •  Display Name •  Type •  Required •  Default Value •  …

Base Properties

String! cmis:policyText   !

String! cmis:name  ! ID! cmis:objectId! ID! cmis:baseTypeId  ! ID! cmis:objectTypeId   ! String! cmis:createdBy    ! DateTime! cmis:creationDate! String! cmis:lastModifiedBy ! DateTime! cmis:lastModificationDate! String! cmis:changetoken!

Boolean! cmis:isImmutable  ! Boolean! cmis:isLatestVersion! Boolean! cmis:isMajorVersion! Boolean! cmis:isLatestMajorVersion! String! cmis:versionLabel! ID! cmis:versionSeriesId ! Boolean! cmis:isVersionSeriesCheckedOut ! String! cmis:versionSeriesCheckedOutBy ! ID! cmis:versionSeriesCheckedOutId ! String! cmis:checkinComment! Integer! cmis:contentStreamLength! String! cmis:contentStreamMimeType ! String! cmis:contentStreamFileName   ! ID! cmis:contentStreamId  !

ID! cmis:parentId! String! cmis:path  ! ID (multi)! cmis:allowedChildObjectTypeIds !

ID! cmis:sourceId  ! ID! cmis:targetId   !

All objects Documents

Folders

Relationships Policies

Content Streams

* Document •  Mime Type •  Length

Content Stream •  Stream Id

Rendition •  Kind •  Mime Type

* Maximum length is repository specific

Access Control

Object ACL

ACE •  Principal •  Permissions •  Direct

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

Document Versioning

V1 Minor

V2 Major

Ve

rsion

Serie

s

Document

PWC

checkout

checkin

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

V3 Major

Policies

* Note: Optional Capability

Repository specific Policies

Client

Document

Retention Security …

apply

Change Log

Create Update Delete

Change Events

Client logs discover

Repo

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, cmis:lastModificationDate FROM cmis:document WHERE cmis:lastModifiedBy = 'admin' ORDER BY cmis:lastModificationDate DESC

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

SELECT cmis:name, cmis:contentStreamLength FROM cmis:document WHERE IN_TREE('<folderObjectId>') AND cmis:contentStreamLength > 100000 ORDER BY cmis:contentStreamLength

CMIS Services

Browse Inspect

Repository -  Get Server Information -  Get Type Definitions

Navigation - Walk Folder / Doc Hierarchy - Get Checked-out

Discovery - Issue Query - Get Change Log

Object - Read Content - Get Properties - Get ACLs - Get Allowable Actions

Versioning -  Walk Version History

Relationship -  Traverse Relationship(s)

Policy -  Get Applied Policies

Act

Object - Write Content - Set Properties - Create Folder / Doc / Relation - Delete -  Move -  Set ACLs

Versioning - Check-out / In - Cancel Check-out - Delete Version(s)

Policy - 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)

•  Don’t bother … There are Open Source libraries for that

Apache Chemistry

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

TM

Main Objective

•  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.

Developers should focus on the CMIS domain model!

Apache Chemistry

Application

Libraries (ORM, connection pools, etc.)

ODBC / JDBC

SQL

Relational DB Content Repository

CMIS Domain Model

Apache Chemistry

CMIS Bindings

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 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

You want this API!

OpenCMIS Client Interfaces

CmisObject

Session DocumentFolder Policy RelationshipSessionFactory «creates»

RepositoryInfo

ContentStream

ObjectType

FolderType DocumentType RelationshipTypePolicyType

Rendition

0..n

FileableCmisObject

Property0..n

PropertyDefinition9..n

1 0..n

ChangeEvents

ChangeEvent0..n

«loads»

Repository

«creates»«loads»

ObjectId

AllowableActions ACL

ACE0..n

QueryResult

«loads»

0..n

0..n0..n

0..n

«loads»

PropertyData0..n

«loads»

sourcetarget

OpenCMIS Main Client Interfaces

CmisObject

DocumentFolder Policy Relationship

ContentStream

Rendition

FileableCmisObject

Property0..n

ObjectIdAllowableActions ACL

ACE0..n

0..n

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. It’s really simple.

OpenCMIS Sessions

•  CMIS is stateless!

•  OpenCMIS introduces a session concept to support caching o  It’s 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 don’t 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