|
|
OpenCMIS Cookbook
Find and share OpenCMIS best practices here.
CMIS Client
Connecting to a CMIS repository
Connecting to a CMIS repository by AtomPub
SessionFactory sessionFactory = SessionFactoryImpl.newInstance();
Map<String, String> parameter = new HashMap<String, String>();
parameter.put(SessionParameter.USER, "user");
parameter.put(SessionParameter.PASSWORD, "password");
parameter.put(SessionParameter.ATOMPUB_URL, "http:); // URL to your CMIS server.
parameter.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
parameter.put(SessionParameter.LOCALE_ISO3166_COUNTRY, "");
parameter.put(SessionParameter.LOCALE_ISO639_LANGUAGE, "en");
parameter.put(SessionParameter.LOCALE_VARIANT, "US");
Session session = null;
try {
Repository soleRepository = sessionFactory.getRepositories(parameter).get(0);
session = soleRepository.createSession();
}
catch(CmisConnectionException e) {
}
catch(CmisRuntimeException e) {
}
Connecting to SharePoint 2010
While connecting via AtomPub is straight forward, connecting via Web Services is a bit tricky.
AtomPub
The service document URL is http://<host>/_vti_bin/cmis/rest/<SPList>?getrepositoryinfo .
Since this sends the password as plain text, HTTPS is strongly recommended.
Web Services
- Download the WSDL with a web browser and store it on your local disk. The WSDL URL is http://<host>/_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 under the hood. If this interferes with your environment, you are on your own.)
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 for details.
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().
CmisObject object = session.getObject(id);
object.refresh();
object.refreshIfOld(60 * 1000);
- Turn off the session cache completely.
session.getDefaultContext().setCacheEnabled(false);
- Turn off caching for this getObject() call.
OperationContext oc = session.createOperationContext();
oc.setCacheEnabled(false);
CmisObject object = session.getObject(id, oc);
- Clear the session cache (not recommended).
Getting the id of an object from its path
String path = "/User Homes/customer1/document.odt"
CmisObject object = getSession().getObjectByPath(path);
String id = object.getId();
Reading a file
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
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<CmisObject> children = folder.getChildren(operationContext);
ItemIterable<CmisObject> page = children.skipTo(skipCount).getPage();
Iterator<CmisObject> pageItems = page.iterator();
while(pageItems.hasNext()) {
CmisObject item = pageItems.next();
}
Retrieving Document objects from query results
String myType = "my:documentType";
String queryString = "SELECT * FROM " + myType;
ObjectType type = session.getTypeDefinition(myType);
PropertyDefinition<?> objectIdPropDef = type.getPropertyDefinitions().get(PropertyIds.OBJECT_ID);
String objectIdQueryName = objectIdPropDef.getQueryName();
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.
CmisObject object = ...
List<CmisExtensionElement> extensions = object.getExtensions(ExtensionLevel.PROPERTIES);
if(extensions == null) {
return;
}
for(CmisExtensionElement ext: extensions) {
if("myExtension".equals(ext.getName()) {
for(CmisExtensionElement child: ext.getChildren()) {
System.out.println(child.getName() + ": " + child.getValue());
}
}
}
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
{
RepositoryServicePortClient repService = GetRepositoryService("https:, "test", "test");
NavigationServicePortClient navService = GetNavigationService("https:, "test", "test");
ObjectServicePortClient objService = GetObjectService("https:, "test", "test");
cmisRepositoryEntryType[] repositoryEntries = repService.getRepositories(null);
foreach (cmisRepositoryEntryType repositoryEntry in repositoryEntries)
{
Console.WriteLine("Repository: " + repositoryEntry.repositoryName + " (" + repositoryEntry.repositoryId + ")");
cmisRepositoryInfoType repositoryInfo = repService.getRepositoryInfo(repositoryEntry.repositoryId, null);
Console.WriteLine(" Info:");
Console.WriteLine(" Description: " + repositoryInfo.repositoryDescription);
Console.WriteLine(" Product: " + repositoryInfo.vendorName + " / " + repositoryInfo.productName + " " + repositoryInfo.productVersion);
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 + ")");
}
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"));
String baseType = GetIdPropertyValue(obj.properties, "cmis:baseTypeId");
if ("cmis:document".Equals(baseType))
{
Int64? size = GetIntegerPropertyValue(obj.properties, "cmis:contentStreamLength");
Console.WriteLine(" Size: " + size);
cmisContentStreamType content = objService.getContentStream(repositoryInfo.repositoryId, objId, null, null, null, null);
Console.WriteLine(" MIME type: " + content.mimeType);
byte[] bytes = content.stream; 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];
}
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];
}
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]);
}
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];
}
break;
}
}
return result;
}
}
}
Reading metadata and content from a CMIS repository
TODO
Creating and updating CMIS objects
TODO
Using the query parser
TODO
CMIS Server
Adding CMIS extensions
(since OpenCMIS 0.2.0)
ObjectData object = ...
String typeId = "MyType";
String objectId = "1111-2222-3333";
String name = "MyDocument";
String ns = "http:;
List<CmisExtensionElement> extElements = new ArrayList<CmisExtensionElement>();
Map<String, String> attr = new HashMap<String, String>();
attr.put("type", typeId);
extElements.add(new CmisExtensionElementImpl(ns, "objectId", attr, objectId));
extElements.add(new CmisExtensionElementImpl(ns, "name", null, name));
List<CmisExtensionElement> extensions = new ArrayList<CmisExtensionElement>();
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">
<objectId type="MyType">1111-2222-3333</objectId>
<name>MyDocument</name>
</exampleExtension:exampleExtension>
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:
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:
<bean id="CmisLifecycleBean" class="org.example.mycmisservice.CmisLifecycleBean">
<property name="cmisServiceFactory" ref="CmisServiceFactory" />
</bean>
<bean id="CmisServiceFactory" class="org.example.mycmisservice.MyCmisServiceFactory">
</bean>
|
|
|