Tuesday, April 3, 2012

Solving the Property 'foo' is a DateTime property! CMIS issue with Chemistry and Alfresco

Recently, I worked on CMIS and Alfresco 4 for a client.
It is a standard project. Everything is in Java with Maven. We developped an Alfresco custom model to fit the needs of the client...

For interoperability purpose and to avoid too much extra coding on the Alfresco side, we decided to use CMIS...

We ran into a Property 'foo' is a DateTime property! when trying to create a document using CMIS.
I read message from people complaining about the issue on the web but no solution about how to fix it. Here is how to do it.

The truth is in the source code


When you have a Date or a DateTime Java object, don't push it directly into Chemistry.
Instead, you must wrap it into a GregorianCalendar object.

The piece of code which teaches you about it is located in the Chemistry source code:

org.apache.chemistry.opencmis.client.runtime.repository.ObjectFactoryImpl.java:440:

} else if (definition instanceof PropertyDateTimeDefinition) {
    if (firstValue == null) {
        propertyData = bof.createPropertyDateTimeData(id, (List) null);
    } else if (firstValue instanceof GregorianCalendar) {
        propertyData = bof.createPropertyDateTimeData(id, (List) values);
    } else {
        throw new IllegalArgumentException("Property '" + id + "' is a DateTime property!");
    }
}
As you can see, whenever you send a DateTime or a Date, Chemistry tries to get a GregorianCalendar object.So all we have to do is to provide it such an object!

An example!

Consider the custom model below:

<!-- Custom model name is myModel. -->
<type name="mymodel:myContent">
    <title>Custom Content</title>
    <parent>cm:content</parent>
    <archive>true</archive>
    <properties>
        <property name="mymodel:registerDate">
            <type>d:date</type>
            <mandatory>false</mandatory>
            <index enabled="true">
                <atomic>true</atomic>
                <stored>false</stored>
            </index>
        </property>
    </properties>
</type>


As you can see, we have a very simple custom type which adds only a registerDate.

Now how would you create a document with the registerDate property through CMIS?

Let's take the create a document example from the Apache Chemistry project website at: http://chemistry.apache.org/java/examples/example-create-update.html customized for our custom model.

// Initialization.
Folder parent = ....
String name = "myNewDocument.txt";
Date aRegisterDate = new Date();

// properties
// (minimal set: name and object type id)
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PropertyIds.OBJECT_TYPE_ID, "D:mymodel:myModel");
properties.put(PropertyIds.NAME, name);

// The registerDate.
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(aRegisterDate);
properties.put("mymodel:registerDate", cal);

// content
byte[] content = "Hello World!".getBytes();
InputStream stream = new ByteArrayInputStream(content);
ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(content.length), "text/plain", stream);

// create a major version
Document newDoc = parent.createDocument(properties, contentStream, VersioningState.MAJOR);


As you can see, registerDate is a GregorianCalendar object. If you simply put the aRegisterDate object, you would have received the following exception message:
Property 'mymodel:registerDate' is a DateTime property is returned.

But with the GregorianCalendar object instead, it works!