Saturday, May 9, 2015

Nuxeo Automation Scripting with Nashorn

In March, Nuxeo Platform Fast Track 7.2 was released.  One new feature of that release is Automation Scripting enabled by Java 8 and Nashorn.

Nashorn replaces the Rhino Javascript scripting engine in Java 8.  Nashorn is based on JSR 262 and provides better compliance with the ECMA normalized Javascript specification.  Compared to Rhino, the performance and memory usage of Nashorn is significantly better.

Thierry Delprat wrote a blog that introduces Nuxeo Automation Scripting with Nashorn.

I wanted to test out the new feature, so I thought that I'd apply scripting to a "drop folder" use case.  In a "drop folder"scenario, an action is triggered that processes and then files documents as they are created and dropped into a folder.

This is typically how imports from a capture product like Ephesoft are handled.  For example, in the Ephesoft case, scanned images are written to a repository folder using CMIS, and then a rule or action associated with the folder pushed to from Ephesoft further processes document metadata and ultimately files the document into a target folder.

The Drop Folder Scenario

I wanted to see how easy it would be to use Nuxeo Automation Scripting to create a "drop folder" script.

For this test scenario, I created two Workspaces in Nuxeo called "Drop Folder" and "Target Folder".



Under Target Folder, I created the following three folders:


The idea for the test script is that documents will be uploaded into the "Drop Folder".  Based on the mimetype of the document, it will be moved into the "Target Folder" area and filed under "PDF Files" if the document is PDF, under "Word Files" if the mimetype is Word, or otherwise filed under "Other Files".

In addition, the description field for the document will be updated with information stating that the document was autofiled and the time the file was made.

Implementation

To implement this, in Nuxeo Studio, I first created an Automation Script called "OnImportScript" and an Event Handler called "OnDocImport".


The event handler tracks the "Document created" events and is triggered when items are created in the folder "/default-domain/workspaces/Drop Folder".  The operation that is run when the event is triggered is called OnImportScript.

Here is the screen for configuring the event handler.


Next I filled in the Javascript code that runs when the event triggers.  The Javascript code for the OnImportScript is shown below.  In that code, the run() method will be called to start the processing.

The run() method identifies the location of Target Folder and moves the document based on the mimetype.


var WORD_MIMETYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
var PDF_MIMETYPE = "application/pdf";

var WORD_FOLDER = "Word Files";
var PDF_FOLDER = "PDF Files";
var OTHER_FOLDER = "Other Files";
var TOP_TARGET_FOLDER = "Target Folder";

//  Get the parent node for the current node
function getParentFolder(node)
{
    // Get the parent reference -- org.nuxeo.ecm.core.api.DocumentRef
  var parent = node.getParentRef();
  return Repository.GetDocument(node, { 'value': parent.toString() });  
}

// Return a child of a folder by name
function getChildByName(fldr, childName)
{
  if(! fldr.getDocumentType().isFolder() ) return null;
  
  var children = Document.GetChildren(fldr, {});

  if(children==null) return null;
  
  for each(var child in children)
  {
      if(child.getName().equals(childName))  return child;
  }

  return null;
}

function getFolderChild(fldr, childName)
{
  var child = getChildByName(fldr, childName);
  if(child)  return child;
  
  // Create the child folder if it doesn't exist
  if(! fldr.getDocumentType().isFolder() ) return null;
  return Document.Create(fldr, { 'type': 'Folder', 'name': childName });

}

//  ctx --  java.util.HashMap
//  input -- org.nuxeo.ecm.core.api.impl.DocumentModelImpl
//  params --  java.util.HashMap
function run(ctx, input, params) {
  
  // Event is instance of org.nuxeo.ecm.core.event.impl.EventImpl
  // If the event isn't "Create Document", then return
   if(!ctx.Event.getName().equals("documentCreated")) return;
   
  //  If the input isn't a document, then return
  if( input===null || !input.getClass().getName().equals("org.nuxeo.ecm.core.api.impl.DocumentModelImpl") ) return;
  
  // If the input is a folder and not a document, ignore it
  if( input.getDocumentType().isFolder() ) return null;
  
  // Collect some information about the document
  var doc = input;
  var docBlob = Document.GetBlob(doc, {});
  var mimeType = docBlob.getMimeType();
  
  var dropFolderNode   = getParentFolder(doc);
  var dropFolderParent = getParentFolder(dropFolderNode);
  var targetFolder =  getFolderChild(dropFolderParent, TOP_TARGET_FOLDER); 
  
  // File the incoming document based on its mimetype
  var targetFolderSub;
  if(mimeType.equals(PDF_MIMETYPE))
  {
      targetFolderSub = getFolderChild(targetFolder, PDF_FOLDER);
  }
  else if(mimeType.equals(WORD_MIMETYPE))
  {
      targetFolderSub = getFolderChild(targetFolder, WORD_FOLDER);
  }
  else
  {
     targetFolderSub = getFolderChild(targetFolder, OTHER_FOLDER);
  }
  
  //  File the document by moving it to the target folder
  if(targetFolderSub != null)
  {
     // Move the document to the correct target folder
     Document.Move(doc, { 'target': targetFolderSub.getId()} );
     var now = new Date();
     Document.SetProperty(doc,{"xpath":'dc:description', "save":true, "value":"Autofiled from folder '" + dropFolderNode.getName() + "' at " + now.toLocaleString()  });
  }

} 

Results

To test, I created documents in the Drop Folder and saw that the Document created event successfully triggered and filed the documents to the correct target folders based on the mimetype.

I was happy with the results, although my testing was minimal.  The purpose of this was just to see how Nuxeo Automation Scripting works and to validate that the approach could be used for creating Javascript-based folder rules, although the approach isn't limited to just putting rules on folders.

No comments:

Post a Comment