Tag: Alfresco API

Cool things you can do in Alfresco with cmis:item support

allyoursysbaseI’ve been taking a look at the newly-added support for cmis:item in Alfresco. As a refresher for those who may not be familiar, cmis:item is a new object type added to the CMIS 1.1 specification. Alfresco added support for CMIS 1.1 in 4.2 but did not immediately add support for cmis:item, which is optional, according to the spec. Now cmis:item support is available in Alfresco in the cloud as well as the nightly builds of 4.3.a Community Edition.

So what is cmis:item?

We’ve all written content-centric applications that have included objects that don’t have a content stream. You might use one to store some configuration information, for example, or maybe you have some other object that doesn’t naturally include a file that needs to be managed as part of it. There are a few approaches to this in Alfresco:

  1. Create your custom type as a child of sys:base (or cm:cmobject if you don’t mind your objects being subject to the file name constraint)
  2. Create your custom type as child of cm:content and simply do not set a content stream
  3. Ignore the content model altogether and use the attribute service

I’m not going to cover the third option in this post. If you want to learn more about the attribute service you should take a look at the Tech Talk Live we did in April.

The second option is fine, but then you’ve got objects with content properties that will never be set. Your objects look like they want to be documents, but they really aren’t because you don’t expect them to ever have a file as part of the object. Not the end of the world, but it’s kind of lazy and potentially confusing to developers that come after you.

The first option is what most people go with, but it has a drawback. Instances of types that do not extend from cm:content or cm:folder are invisible to CMIS 1.0. Not only are those objects invisible to CMIS 1.0 but relationships that point to such objects are also invisible. Depending on how much you use CMIS in your application this could be a fairly severe limitation.

Thankfully, CMIS 1.1 addresses the issue with a new object type called cmis:item. It’s made precisely for this purpose.

What can I do with it out-of-the-box?

Even if your custom content model doesn’t need a “content-less object” you can still benefit from cmis:item support. Let me walk you through my five favorite object types that you can now work with via cmis:item support in CMIS 1.1 that were not previously available: Category, Person, Group, Rating, and Rule. I tested everything I’m showing you here using Alfresco 4.3.a Community Edition, Nightly Build (4/27/2014, (r68092-b4954) schema 7003) and Apache Chemistry OpenCMIS Workbench 0.11.0.

Category

Man, if I had a bitcoin for every person I’ve seen asking how to get the categories of a document via CMIS, I’d have a garage full of Teslas. With cmis:item support, it’s easy. Here’s how you get a list of every category in the system with a CMIS Query Language (CQL) query:

SELECT * FROM cm:category

That returns a list of cm:category objects that represent each category in the system. Note that this is a flat list. In Alfresco, categories are hierarchical. I’m not sure what the plan to address that is, to be honest.

Now suppose you have an object and you want to know the categories that have been assigned. Here is some Groovy code that does that:

(Can’t see the code? Click here)

Categories live in a property called “cm:categories”. It’s a multi-value field that contains the Alfresco node references for each category that has been assigned to a document. Once you get that list you can iterate over them and fetch the cm:category object to figure out the category’s human-readable name. That’s pretty cool and wasn’t possible before CMIS 1.1 support.

How about assigning existing categories to documents? Sure, no problem. Here’s how.

(Can’t see the code? Click here)

This is a little Groovy function that takes a full path to a document and the name of a category. Obviously it depends on your categories being uniquely-named.

First, it finds the category by name using CQL and snags its Alfresco node reference.

Next, it checks to see if the cm:generalclassifiable aspect has already been added to the document and adds it if it has not.

Finally, it gets the current list of categories from the cm:categories property and adds the new category’s node reference to it.

I started to look at creating new categories with CMIS, but it isn’t immediately obvious how that would work due to the hierarchical nature of categories. The only parent-child association supported by CMIS is the one implied by folder-document relationship. I’ll ask around and see if there’s a trick.

That’s it for categories. Let’s look at Person objects next.

Person

Here’s another frequently-asked how-to: How do I query users through CMIS? Before cmis:item support you couldn’t do it, but now you can. For example, here is how you can use CQL to find a list of the Person objects in Alfresco:

SELECT * FROM cm:person

You can qualify it further based on properties of cm:person. For example, maybe I want all users who’s first name starts with “Te” and who work for an organization that starts with “Green”. That query looks like:

SELECT * FROM cm:person where cm:firstName like 'Te%' and cm:organization like 'Green%'

Suppose you wanted to find every Alfresco Person object that has a city starting with “Dallas” and you want to set their postal code to “75070”. Ignoring cities named “Dallas” that aren’t in Texas (like Dallas, Georgia) or the fact that there are multiple zip codes in Dallas, Texas, the code would look like this:

(Can’t see the code? Click here)

That’s it for Person objects. Let’s look at Group objects.

Group

Similar to querying for Person objects, cmis:item support gives you the ability to query for groups–all you have to know is that groups are implemented as instances of cm:authorityContainer. Here’s the query:

SELECT * FROM cm:authorityContainer

Unfortunately, it doesn’t seem possible to use CMIS to actually add or remove members to or from the group. Maybe that will change at some point.

Rating

It’s easy to query for ratings:

SELECT * FROM cm:rating

But it’s hard to do anything useful with those objects because, at least in this nightly release, you can’t follow the relationships from or two a rating. As a sidenote, you can get the count and total for a specific node’s ratings by getting the value of the cm:likesRatingSchemeCount and cm:likesRatingSchemeTotal properties respectively. But that’s not related to cmis:item support.

Rule

Rules are a powerful feature in Alfresco that help you automate document handling. Here’s how to use a query to get a list of rules in your repository:

SELECT * FROM rule:rule

Rules are so handy you might end up with a bunch of them. What if you wanted to find all of the rules that matched a certain criteria (title, for example) so that you could enable them and tell them to run on sub-folders? Here is a little Groovy that does that:

(Can’t see the code? Click here)

First the code uses a join to find the rule based on a title. The property that holds a rule’s title is defined in an aspect and that requires a join when writing CQL.

Then the code simply iterates over the result set and updates the rule:applyToChildren and rule:disabled properties. You could also set the rule’s type, description, and whether or not it runs asynchronously. It does not appear to be possible to change the actions or the filter criteria for a rule through CMIS at this time.

What about custom types?

Custom types? Sure, no problem. Suppose I have a type called sc:client that extends sys:base and has two properties, sc:clientName and sc:clientId. Alfresco automatically makes that type accessible via CMIS. It’s easy to create a new instance and set the value of those two properties. Here’s the groovy code to do it:

(Can’t see the code? Click here)

Did you notice I created the object in a folder? In Alfresco, everything lives in a folder, even things that aren’t documents. In CMIS parlance, you would say that Alfresco does not support “unfiled” objects.

The custom object can be queried as you would expect, including where clauses that use the custom property values, like this:

SELECT * FROM sc:client where sc:clientId = '56789'

In CMIS 1.0 you could not use CMIS to work with associations (“relationships”) between objects that did not inherit from either cm:content (cmis:document) or cm:folder (cmis:folder). In CMIS 1.1 that changed. You can create relationships between documents and folders and items. Unfortunately, in the latest nightly build this does not appear to be implemented. Hopefully that goes in soon!

Summary

The new cmis:item type in CMIS 1.1 is a nice addition to the specification that is useful when you are working with objects that are not documents and do not have a content stream. I showed you some out-of-the-box types you can work with via cmis:item but you can also leverage cmis:item with your custom types as well.

Support for cmis:item requires CMIS 1.1 and either Alfresco in the cloud or a recent nightly build of Alfresco 4.3.

Announcement: Apache Chemistry cmislib 0.5.1 now available

The Apache Chemistry project is pleased to announce that cmislib 0.5.1 is now available (home, docs). Developers can use cmislib to write Python applications against any CMIS-compliant repository such as Alfresco, SharePoint, Nuxeo, and FileNet. You can download the client library from the Apache Chemistry cmislib home page or use Setup Tools to install the library quickly and easily.

This release features support for renditions, so if your repository supports things like thumbnails, you can retrieve a list of those for a given object. The new release also supports passing in arbitrary HTTP headers. That is one way to enable authentication scenarios beyond basic authentication such as OAuth2, which is the authentication mechanism Alfresco in the Cloud uses.

If you are brand new to CMIS, here are a few links to get you started:

In addition, I’ve been working on an Apache Chemistry and CMIS in Action book with Jay Brown and Florian Mueller. The book is available now through Manning’s early-access program.

The Public Alfresco API is Now Live: How to Get Started

At JavaOne this morning, Alfresco announced the general availability of the public Alfresco API. The public Alfresco API allows developers to create custom applications (desktop, mobile, or cloud) that persist content to Alfresco in the Cloud. The API includes CMIS plus some Alfresco REST calls that provide functionality CMIS does not cover.

Eventually, this public, versioned API will work against Alfresco in the Cloud as well as Alfresco running on-premise. For now, it is only for Alfresco in the Cloud, although the CMIS calls will work against both. (For example, on my flight to California I worked on an example using CMIS and my local repository. When I got to the hotel, I added in the OAuth authentication and my example worked against Alfresco in the Cloud).

To use the Alfresco API, all you have to do is become a registered developer at http://developer.alfresco.com. Once you’ve verified your email address, you can add applications to your profile. Each application has a unique authentication key and a secret. OAuth2 is used to handle authentication.

Once you have your authentication key and secret, you can start making calls against the API. Calls that hit the Alfresco REST part of the API return JSON. Calls that leverage CMIS return AtomPub XML. If you already know how to make CMIS calls, you already know how to use the Alfresco API–just grab the latest version of your favorite CMIS client, like OpenCMIS or cmislib, and pass in the authorization header. I believe you must use the 0.8.0-SNAPSHOT of OpenCMIS. If you are using cmislib, you’ll definitely need 0.5.1dev.

Here are some resources to help you get started:

If you want to discuss the public Alfresco API, use this forum and any of our other normal community channels like #alfresco on IRC or the Alfresco Technical Discussion Google Group.

Of course we’ll be talking about the API at DevCon in both Berlin and San Jose this November, so don’t forget to register!

Also, Peter Monks and I will be doing this month’s Tech Talk Live on the new API, so if you weren’t lucky enough to be in San Francisco for our session at JavaOne or our booth, you can catch the details there as well.