A big event occurred recently. Something huge I did not see coming. Some days ago, I woke up in the morning and guess what? The year had changed. Can you believe it? Gosh! Is time running at light-speed or what? It’s the New Year. So - Happy New Year to you all!

Now, let’s start my first blog of the year. It’s about events and event handlers.

Event Handlers are at the core of many Nuxeo applications, because they are a great place to manage and centralize business rules. Basically, an event handler (also called a listener) subscribes to an event, and when this event occurs, the handler is run. It is actually subtler than that, because the event handler also defines conditions for which it allows itself to be triggered. So, for example, an event handler could subscribe to the “document created” event, but will be executed only if the created document is a File (i.e. it will not run if it is a Folder, or a Picture).

And Nuxeo provides many many(1) events. From the Studio point of view, we have this:

01-EventsList-1-80

Wait.

Wait wait wait.

I just wrote "many many” and we can only see four events here. Where are the others? Actually, they are in the scrollable list. Of course. As of today, with Studio 2.16, the full list is(2):

01-EventsList-2-80

You can find more information on each event here.

So, in Studio, you select the event(s), you setup the enablement, and then you pick-up a chain to be run when the event fires and the enablement conditions are met.

Now a little story about the reason why I am writing this blog. I had the following need: When “Empty document created” is fired on my Claim document, I want to pre-fill some values. But these default values depend on the parent document. So for example, say I have a claim:department field. If the Claim is created inside a Folder, then the department must be set to “Marketing”. In all other cases, the department must be set to “Management”.

The point is, in the context of the “Empty document created” event, the current document has no parent yet. I mean, from the automation chain, you cannot use something like @{Document.parent.type …etc…}.

Well. Technically, you can: After all, you can do whatever you want(3) can’t you? This is a good opportunity to see the awesome new error messages of 5.8 - look at the server log and check the description of the error. In case you want to save some time, I’m telling you: Document.parent is null, so Document.parent.type generates the hell in the log file.

How can I get the type of the parent in this context? After spending some time searching, I found myself asking for help from my colleagues. I received an answer because they are cool, patient, understanding and kind to me(4). The answer was: “Use the parentPath value of the event’s options”.

All I had to do then was find where these options were, and how I could use them. Well, quite simply: RTFM. It’s described in Understand Expression and Scripting Languages Used in Nuxeo. More precisely, in the Event Handlers part of the page. At this time, there was nothing about “parentPath”, “destinationRef” and “Availability of These Properties”: That’s also how we improve the documentation. We get in trouble, we clear the trouble, and we update the doc so other people will not feel the same pain.

Back to this story: All I had to do was to get the parent document using its path with the following expression:

Event.context.getProperty(“parentPath”)

My final chain triggered for the “Empty document created” event. For a Claim document it is…

Fetch > Context Document(s)
Push & Pop > Push Document
Fetch > Document
value: @{Event.context.getProperty("parentPath")}
Execution Context > Set Context Variable
name: parentIsFolder
value: @{Document.type == “Folder”}
Push & Pop > Pop Document
Document > Update Property
value: @{parentIsFolder ? “Marketing” : “Management”}
xpah: claim:department
save: no


…and it works like a charm. Important reminder: Make sure the “save” box is not checked. If you do save the document in the context of the Empty document created event, the server will gently throw an error.

Now, let’s push this a bit further. If you want to get a list of available properties for a given event, then a good trick is to use @{Event.context.getProperties().toString()}.

Note
When the documentation states that an expression used in MVEL is an object, you can look at the JavaDoc of the object, to check what's interesting. So for instance, here, you have an open JavaDoc page, so find the Event class. Then, you follow the EventContext link and you see this getProperties method.


For quick testing, create a new event handler. Select all and every possible event, activate it for File, and bind it to a chain that logs the result of this expression. Something like:

Fetch > Context Document(s)
Notification > Log
level: warn
Message: @{Event.getName()}: @{Event.context.getProperties().toString()}


Save, update the server, play with a File and watch the server.log file: You will find all the events and all the available properties for each event that occurred. For example, after creating a new File, you will have:

[code]
emptyDocumentModelCreated: {category=eventDocumentCategory, BLOCK_JMS_PRODUCING=true, sessionId=default-8821762671641624678, repositoryName=default, comment=null, parentPath=/default-domain/workspaces/ws}
aboutToCreate: {destinationRef=/default-domain/workspaces/ws, category=eventDocumentCategory, sessionId=default-8821762671641624678, destinationName= TheNewFile, repositoryName=default, comment=null}
documentCreated: {destinationRef=/default-domain/workspaces/ws, category=eventDocumentCategory, sessionId=default-8821762671641624678, destinationName=TheNewFile, repositoryName=default, comment=null, documentLifeCycle=project}

[/code]

Happy New Year event!

(1) Not a duplicate. I really mean “a lot”
(2) Display the Web Inspector, inspect the Select object, change its height.
(3) © Status Quo
(4) Let them be in a good mood for the next question