OpenCMIS Cookbook
Find and share OpenCMIS best practices here.
CMIS Client
Connecting to a CMIS repository
Connecting to a CMIS repository by AtomPub
// Default factory implementation of client runtime.
SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
Map<String, String> parameter = new HashMap<String, String>();
// User credentials.
parameter.put(SessionParameter.USER, "user");
parameter.put(SessionParameter.PASSWORD, "password");
// Connection settings.
parameter.put(SessionParameter.ATOMPUB_URL,
"http://localhost:8080/alfresco/service/cmis"); // URL to your CMIS server.
// parameter.put(SessionParameter.REPOSITORY_ID, "myRepository"); // Only necessary if there is more than one repository.
parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
// Session locale.
parameter.put(SessionParameter.LOCALE_ISO3166_COUNTRY, "");
parameter.put(SessionParameter.LOCALE_ISO639_LANGUAGE, "en");
parameter.put(SessionParameter.LOCALE_VARIANT, "US");
// Create session.
Session session = null;
try {
// This supposes only one repository is available at the URL.
Repository soleRepository =
sessionFactory.getRepositories(parameter).get(0);
session = soleRepository.createSession();
}
catch(CmisConnectionException e) {
// The server is unreachable
}
catch(CmisRuntimeException e) {
// The user/password have probably been rejected by the server.
}
h4. Connecting to SharePoint 2010
While connecting via AtomPub is straight forward, connecting via Web
Services is a bit tricky.
h5. AtomPub
The service document URL is
http:///_vti_bin/cmis/rest/?getrepositoryinfo .
Since this sends the password as plain text, HTTPS is strongly
recommended.
h5. Web Services
# Download the WSDL with a web browser and store it on your local disk. The
WSDL URL is http:///_vti_bin/cmissoapwsdl.aspx?wsdl .
# Provide file://... URLs to the downloaded WSDL for all OpenCMIS WSDL
session parameters.
# Activate the OpenCMIS NTLM authentication provider.
parameters.put(SessionParameter.AUTHENTICATION_PROVIDER_CLASS, CmisBindingFactory.NTLM_AUTHENTICATION_PROVIDER);
(The NTLM
authentication provider uses [java.net.Authenticator|http://download-llnw.oracle.com/javase/6/docs/api/java/net/Authenticator.html]
under the hood. If this interferes with your environment, you are on your
own.)
h4. Using Cookies
Some repositories are sending HTTP cookies to maintain state (although CMIS
is stateless) or accelerate authentication for subsequent calls. OpenCMIS
ignores these cookies by default. The following code snippet activates
cookies for your application and OpenCMIS. See [this page|http://java.sun.com/docs/books/tutorial/networking/cookies/cookiemanager.html]
for details.
{code:java}
CookieManager cm = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cm);
Understanding the client side cache
Client side caching is turned on by default. That is, getObject() will
first look into the session cache if the object already exists there. If
this is the case, it returns the object without talking to the repository.
So it might return stale objects.
There are multiple ways to deal with that:
* Refresh the object data that is returned from getObject().
{code:java}
CmisObject object = session.getObject(id);
object.refresh(); // contacts the repository and refreshes the object
object.refreshIfOld(60 * 1000); // ... or refreshes the object only if the
data is older than a minute
* Turn off the session cache completely.
{code:java}
session.getDefaultContext().setCacheEnabled(false);
- Turn off caching for this getObject() call.
{code:java}
OperationContext oc = session.createOperationContext();
oc.setCacheEnabled(false);
CmisObject object = session.getObject(id, oc);
* Clear the session cache (not recommended).
{code:java}
session.clear();
Getting the id of an object from its path
{code:java}
String path = "/User Homes/customer1/document.odt"
CmisObject object = getSession().getObjectByPath(path);
String id = object.getId();
h3. Reading a file
{code:java}
CmisObject object = getSession().getObject(session.createObjectId(fileId));
Document document = (Document)object;
String filename = document.getName();
InputStream stream = document.getContentStream().getStream();
Showing a folder's items, with results paging
{code:java}
int maxItemsPerPage = 5;
int skipCount = 10;
CmisObject object = session.getObject(session.createObjectId(folderId));
Folder folder = (Folder)object;
OperationContext operationContext = session.createOperationContext();
operationContext.setMaxItemsPerPage(maxItemsPerPage);
ItemIterable children = folder.getChildren(operationContext);
ItemIterable page = children.skipTo(skipCount).getPage();
Iterator pageItems = page.iterator();
while(pageItems.hasNext()) {
CmisObject item = pageItems.next();
// Do something with the item.
}
h3. Retrieving Document objects from query results
{code:java}
String myType = "my:documentType";
String queryString = "SELECT * FROM " + myType;
// get the query name of cmis:objectId
ObjectType type = session.getTypeDefinition(myType);
PropertyDefinition<?> objectIdPropDef =
type.getPropertyDefinitions().get(PropertyIds.OBJECT_ID);
String objectIdQueryName = objectIdPropDef.getQueryName();
// execute query
ItemIterable<QueryResult> results = session.query(queryString, false);
for (QueryResult qResult : results) {
String objectId =
qResult.getPropertyValueByQueryName(objectIdQueryName);
Document doc = (Document)
session.getObject(session.createObjectId(objectId));
}
Getting CMIS extensions
(since OpenCMIS 0.2.0)
The CMIS specification allows to add extensions at several points in CMIS
data structures (object, properties, allowable actions, ACLs, policies,
etc.).
These extensions are XML fragments for the AtomPub and the Web Services
binding. (It will be something simpler for the upcoming JSON binding.)
Think of it as a tree structure with named node and leafs. Only the leafs
can have a value.
{code:java}
// get an object from somewhere
CmisObject object = ...
// extensions can be attached to different levels
// in this example we get the extensions on the properties level
List extensions =
object.getExtensions(ExtensionLevel.PROPERTIES);
if(extensions == null) {
// this object has no extensions on this level
return;
}
// iterate through the extensions until we find the one we are looking for
for(CmisExtensionElement ext: extensions) {
if("myExtension".equals(ext.getName()) {
// found it, now print the values of the children
for(CmisExtensionElement child: ext.getChildren()) {
System.out.println(child.getName() + ": " + child.getValue());
}
}
}
h3. Connecting from a .Net client via the Web Services binding
This is a very simple C# example that demonstrates how to connect to an
OpenCMIS server via the Web Services binding. Please note that .Net only
allows UsernameTokens over HTTPS.
using System;
using System.ServiceModel;
using OpenCMISClient.OpenCMISServer;
using System.Net;
namespace OpenCMISClient
{
class CMISClientDemo
{
public void DoStuff()
{
try
{
// uncomment the next line if you are using a self signed
SSL certificate
// ServicePointManager.ServerCertificateValidationCallback
= delegate { return true; };
// get hold of the services
RepositoryServicePortClient repService =
GetRepositoryService("https://localhost:8443/opencmis/services/RepositoryService?wsdl",
"test", "test");
NavigationServicePortClient navService =
GetNavigationService("https://localhost:8443/opencmis/services/NavigationService?wsdl",
"test", "test");
ObjectServicePortClient objService =
GetObjectService("https://localhost:8443/opencmis/services/ObjectService?wsdl",
"test", "test");
// get the list of repositories
cmisRepositoryEntryType[](.html)
repositoryEntries = repService.getRepositories(null);
foreach (cmisRepositoryEntryType repositoryEntry in
repositoryEntries)
{
Console.WriteLine("Repository: " +
repositoryEntry.repositoryName + " (" + repositoryEntry.repositoryId +
")");
// get repository info
cmisRepositoryInfoType repositoryInfo =
repService.getRepositoryInfo(repositoryEntry.repositoryId, null);
Console.WriteLine(" Info:");
Console.WriteLine(" Description: " +
repositoryInfo.repositoryDescription);
Console.WriteLine(" Product: " +
repositoryInfo.vendorName + " / " + repositoryInfo.productName + " " +
repositoryInfo.productVersion);
// get all base types of the repository
cmisTypeDefinitionListType typeList =
repService.getTypeChildren(repositoryInfo.repositoryId, null, true, null,
null, null);
Console.WriteLine(" Types:");
foreach (cmisTypeDefinitionType type in typeList.types)
{
Console.WriteLine(" " + type.displayName + " ("
+ type.id + ")");
}
// get all root folder children
cmisObjectInFolderListType children =
navService.getChildren(repositoryInfo.repositoryId,
repositoryInfo.rootFolderId, null, null, true, null, null, false, null,
null, null);
Console.WriteLine(" Root folder:");
foreach (cmisObjectInFolderType objInFolder in
children.objects)
{
cmisObjectType obj = objInFolder.@object;
String objId = GetIdPropertyValue(obj.properties,
"cmis:objectId");
Console.WriteLine(" Name: " +
GetStringPropertyValue(obj.properties, "cmis:name") + " (" + objId + ")");
Console.WriteLine(" Type: " +
GetIdPropertyValue(obj.properties, "cmis:baseTypeId"));
Console.WriteLine(" Created by: " +
GetStringPropertyValue(obj.properties, "cmis:createdBy"));
Console.WriteLine(" Creation date: " +
GetDateTimePropertyValue(obj.properties, "cmis:creationDate"));
// if it is a document, get the size and the
content
String baseType =
GetIdPropertyValue(obj.properties, "cmis:baseTypeId");
if ("cmis:document".Equals(baseType))
{
// get the size
Int64? size =
GetIntegerPropertyValue(obj.properties, "cmis:contentStreamLength");
Console.WriteLine(" Size: " +
size);
// get the content
cmisContentStreamType content =
objService.getContentStream(repositoryInfo.repositoryId, objId, null, null,
null, null);
Console.WriteLine(" MIME type: " +
content.mimeType);
// get the "stream"
byte[](.html)
bytes = content.stream; // really streaming requires some more work
Console.WriteLine(" Stream: " +
(bytes.Length == size ? "ok" : "mismatch"));
}
}
}
}
catch (FaultException<cmisFaultType> fe)
{
Console.WriteLine("CMIS Exception: " + fe.Detail.message);
Console.WriteLine("Type: " + fe.Detail.type);
Console.WriteLine("Code: " + fe.Detail.code);
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
Console.WriteLine(e.StackTrace);
}
Console.ReadKey();
}
public RepositoryServicePortClient GetRepositoryService(String
wsdlUrl, String user, String password)
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security.Mode =
BasicHttpSecurityMode.TransportWithMessageCredential;
RepositoryServicePortClient service = new
RepositoryServicePortClient(binding, new EndpointAddress(wsdlUrl));
service.ClientCredentials.UserName.UserName = user;
service.ClientCredentials.UserName.Password = password;
return service;
}
public NavigationServicePortClient GetNavigationService(String
wsdlUrl, String user, String password)
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security.Mode =
BasicHttpSecurityMode.TransportWithMessageCredential;
NavigationServicePortClient service = new
NavigationServicePortClient(binding, new EndpointAddress(wsdlUrl));
service.ClientCredentials.UserName.UserName = user;
service.ClientCredentials.UserName.Password = password;
return service;
}
public ObjectServicePortClient GetObjectService(String wsdlUrl,
String user, String password)
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security.Mode =
BasicHttpSecurityMode.TransportWithMessageCredential;
binding.TransferMode = TransferMode.Streamed;
ObjectServicePortClient service = new
ObjectServicePortClient(binding, new EndpointAddress(wsdlUrl));
service.ClientCredentials.UserName.UserName = user;
service.ClientCredentials.UserName.Password = password;
return service;
}
public String GetStringPropertyValue(cmisPropertiesType properties,
String id)
{
String result = null;
foreach (cmisProperty property in properties.Items)
{
if (property.propertyDefinitionId.Equals(id))
{
if (property is cmisPropertyString)
{
result = ((cmisPropertyString)property).value[0](0.html)
;
}
break;
}
}
return result;
}
public String GetIdPropertyValue(cmisPropertiesType properties,
String id)
{
String result = null;
foreach (cmisProperty property in properties.Items)
{
if (property.propertyDefinitionId.Equals(id))
{
if (property is cmisPropertyId)
{
result = ((cmisPropertyId)property).value[0](0.html)
;
}
break;
}
}
return result;
}
public Int64? GetIntegerPropertyValue(cmisPropertiesType
properties, String id)
{
Int64? result = null;
foreach (cmisProperty property in properties.Items)
{
if (property.propertyDefinitionId.Equals(id))
{
if (property is cmisPropertyInteger)
{
result = Int64.Parse(((cmisPropertyInteger)property).value[0](0.html)
);
}
break;
}
}
return result;
}
public DateTime? GetDateTimePropertyValue(cmisPropertiesType
properties, String id)
{
DateTime? result = null;
foreach (cmisProperty property in properties.Items)
{
if (property.propertyDefinitionId.Equals(id))
{
if (property is cmisPropertyDateTime)
{
result = ((cmisPropertyDateTime)property).value[0](0.html)
;
}
break;
}
}
}
h3. Reading metadata and content from a CMIS repository
TODO
h3. Creating and updating CMIS objects
TODO
h3. Using the query parser
TODO
h2. CMIS Server
h3. Adding CMIS extensions
_(since OpenCMIS 0.2.0)_
{code:java}
// we want to attach an extension to an object
ObjectData object = ...
// some dummy data
String typeId = "MyType";
String objectId = "1111-2222-3333";
String name = "MyDocument";
// find a namespace for the extensions that is different from the CMIS
namespaces
String ns = "http://apache.org/opencmis/example";
// create a list for the first level of our extension
List<CmisExtensionElement> extElements = new
ArrayList();
// set up an attribute (Avoid attributes! They will not work with the JSON
binding!)
Map attr = new HashMap();
attr.put("type", typeId);
// add two leafs to the extension
extElements.add(new CmisExtensionElementImpl(ns, "objectId", attr,
objectId));
extElements.add(new CmisExtensionElementImpl(ns, "name", null, name));
// set the extension list
List<CmisExtensionElement> extensions = new
ArrayList();
extensions.add(new CmisExtensionElementImpl(ns, "exampleExtension", null,
extElements));
object.setExtensions(extensions);
This should create something like that:
<exampleExtension:exampleExtension
xmlns="http://apache.org/opencmis/example"
xmlns:exampleExtension="http://apache.org/opencmis/example">
1111-2222-3333
MyDocument
Using the server framework with Spring
By default, the OpenCMIS services factory is set up by a context listner
configured in the web.xml. If you want or need Spring to set up the
services factory, remove the context listner from the web.xml and use a
bean like this instead:
{code:java}
public class CmisLifecycleBean implements ServletContextAware,
InitializingBean, DisposableBean
{
private ServletContext servletContext;
private CmisServiceFactory factory;
@Override
public void setServletContext(ServletContext servletContext)
{
this.servletContext = servletContext;
}
public void setCmisServiceFactory(CmisServiceFactory factory)
{
this.factory = factory;
}
@Override
public void afterPropertiesSet() throws Exception
{
if (factory != null)
{
factory.init(new HashMap<String, String>());
servletContext.setAttribute(CmisRepositoryContextListener.SERVICES_FACTORY,
factory);
}
}
@Override
public void destroy() throws Exception
{
if (factory != null)
{
factory.destroy();
}
}
}
The Spring configuration could look like this:
{code:xml}
<bean id="CmisLifecycleBean"
class="org.example.mycmisservice.CmisLifecycleBean">
<bean id="CmisServiceFactory"
class="org.example.mycmisservice.MyCmisServiceFactory">