Apache Chemistry: The Alfresco Open Source Implementation of CMIS


Published on

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.

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Apache Chemistry: The Alfresco Open Source Implementation of CMIS

  1. 1. and Florian Müller, Software Architect
  2. 2. 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
  3. 3. 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!
  4. 4. 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
  5. 5. CMIS Base Types     Document Folder •  Content •  Container •  Renditions •  Hierarchy •  Version History •  Filing Described by Type Definitions Relationship Policy •  Source Object •  Target Object •  Target Object
  6. 6. 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
  7. 7. Base PropertiesAll objects DocumentsString! 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 PoliciesID! cmis:sourceId  ! String! cmis:policyText   !ID! cmis:targetId   !
  8. 8. Content Streams Document * Rendition •  Mime Type •  Kind •  Length •  Mime Type Content Stream •  Stream Id * Maximum length is repository specific
  9. 9. Access Control ACL Object ACE •  Principal •  Permissions •  Direct Permissions cmis:read cmis:write cmis:all <repository specific>
  10. 10. 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
  11. 11. Policies Repository specific Policies Retention Security … Client ly app Document * Note: Optional Capability
  12. 12. 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
  13. 13. 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
  14. 14. Do You Understand These Queries?SELECT cmis:nameFROM cmis:documentWHERE 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
  15. 15. CMIS ServicesBrowse Inspect ActRepository 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 ACLsNavigation Versioning- Walk Folder / Doc -  Walk Version HistoryHierarchy- 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
  16. 16. CMIS Cheat Sheethttp://cmis.alfresco.com/cmis-cheatsheet.pdf
  17. 17. 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
  18. 18. 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
  19. 19. 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.
  20. 20. Apache Chemistry Application Libraries Apache Chemistry (ORM, connection pools, etc.) ODBC / JDBC CMIS Bindings CMIS Domain SQL Model Relational DB Content Repository
  21. 21. 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
  22. 22. HistoryMay 2009: Started as an incubator project by Nuxeo and Day (now Adobe)February 2010: Metaversant contributed cmislibFebruary 2010: Alfresco, OpenText and SAP contributed OpenCMISMay 2010: Alfresco contributed phpclientJanuary 2011: Alfresco contributed DotCMISFebruary 2011: Graduated to a top level project
  23. 23. OpenCMISOpenCMIS 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
  24. 24. Get hold of OpenCMISOpenCMIS 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
  25. 25. OpenCMIS Architecture
  26. 26. 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
  27. 27. 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
  28. 28. OpenCMIS Main Client Interfaces AllowableActions ObjectId ACL 0..n ACE Rendition CmisObject Property 0..n 0..n FileableCmisObject Folder Document Policy Relationship ContentStream
  29. 29. 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
  30. 30. 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.
  31. 31. 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
  32. 32. Connect to a repository – Variant 1// set up session parametersMap<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 sessionSessionFactory factory = SessionFactoryImpl.newInstance();Session session = factory.createSession(parameter);
  33. 33. Connect to a repository – Variant 2// set up session parametersMap<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 oneSessionFactory factory = SessionFactoryImpl.newInstance();List<Repository> repositories = factory.getRepositories(parameter);Session session = repositories.get(0).createSession();
  34. 34. Using the SessionRepositoryInfo 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(); ! }!}!
  35. 35. CMIS Workbench Live samples with the CMIS Workbench …
  36. 36. Navigationimport 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 folderFolder root = session.getRootFolder();String rootFolderName = root.getName();println "Root folder: ${rootFolderName}n"// print root folder childrenfor(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}" } */}
  37. 37. Pagingimport 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 "--------------------------------------"!}!
  38. 38. Propertiesimport 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 ""}
  39. 39. Contentimport 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)!!
  40. 40. Queryimport 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 "--------------------------------------"}
  41. 41. Foldersimport 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);!!
  42. 42. Documentsimport 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 documentString 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 documentnewDoc.delete(true);void printProperties(CmisObject object) { object.properties.each { println "${it.id}: ${it.firstValue}" } println "--------------------------------------"}
  43. 43. 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.
  44. 44. 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
  45. 45. 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…
  46. 46. Questions