Content Engine API ♥ Java 8

Code on github

WebSphere versions 8.5.5 (with the correct service packs) and 9 open up support for the Java 8 SDK in combination with IBM FileNet Content Manager. One of the major features in the Java 8 SDK is the support for lambda expressions and the Stream API. This combination leads to more readable and concise code, making simple things even more simpler.

The Content Engine API of course pre-dates the Java 8 SDK, so out of the box there is no support for the Stream API. However this thread on stack overflow inspired the creation of a wrapper class. The wrapper class takes an iterator based collection and converts its into a Stream. The wrapper class is a type safe solution because it contains a wrapper method for all the classes in the com.filenet.api.collection package.

Most of the code of the wrapper class is generated taking the Jace.jar file as the input. The code to generate the code is also included, so feel free to regenerate the code for newer versions of the API.

You can download the wrapper class from here, and next add it to your project. For convenience, first do a static import of the asStream method from the CEAPIStreams class in your Java class:

import static com.ecmdeveloper.jace.streams.CEAPIStreams.asStream;

Next you can write code like this, printing all the names of the documents in a folder:

Folder folder = Factory.Folder.fetchInstance(os, path, filter);
asStream(folder.get_ContainedDocuments())
  .forEach( document -> System.out.println(document.get_Name()));

To show the full potential of this way of writing, consider this iterator based piece of code:

Iterator<Folder> iterator = folder.get_SubFolders().iterator();
while (iterator.hasNext()) {
  Folder subFolder = (Folder) iterator.next();
  if ( !subFolder.getProperties().getBooleanValue("IsHiddenContainer") ) {
    System.out.println(subFolder.get_Name());
  }
}

This is perhaps the shortest way you could print out the names of all the subfolders which are not hidden using the old way.

This piece of code can be rewritten using the Stream API and lambda expressions in the following way:

Predicate<Folder> isNotHidden =
  subFolder -> !subFolder.getProperties().getBooleanValue("IsHiddenContainer");

asStream(folder.get_SubFolders())
  .filter(isNotHidden)
  .forEach(subFolder -> System.out.println(subFolder.get_Name()));

Besides being a little bit shorter, this code also clearly states what it’s intentions are: Get the subfolders, filter them with the isNotHidden predicate and next use the forEach construct to print the name.

The real benefit comes when you want to add some more functionality to the code, for instance printing the names in alphabetic order.

Predicate<Folder> isNotHidden =
  subFolder -> !subFolder.getProperties().getBooleanValue("IsHiddenContainer");

asStream(folder.get_SubFolders())
  .filter(isNotHidden)
  .map(subFolder -> subFolder.get_Name())
  .sorted()
  .forEach(name -> System.out.println(name));

By using the map function the folder stream is converted to a String stream containing the folder names and feeding that stream through the sorted function will result in a sorted stream.

Next, to show off, we can add more syntactical sugar by using the Java 8 method reference construction. Using this technique the code can be made even more compact:

Predicate<Folder> isNotHidden =
  subFolder -> !subFolder.getProperties().getBooleanValue("IsHiddenContainer");

asStream(folder.get_SubFolders())
  .filter(isNotHidden)
  .map(Folder::get_Name)
  .sorted()
  .forEach(System.out::println);

Instead of printing the names, you could also create a new list containing the names using the collect method:

List<String> names = asStream(folder.get_SubFolders())
  .map(Folder::get_Name)
  .collect(Collectors.toList());

The different possibilities to play with this are endless. For instance this code will sort the folders based on the the creation date of the folder:

Comparator<Folder> byDateCreated =
  (f1, f2) -> f1.get_DateCreated().compareTo( f2.get_DateCreated() );

asStream(folder.get_SubFolders())
  .sorted(byDateCreated)
  .map(Folder::get_Name)
  .forEach(System.out::println);

Or even shorter by again using method reference and the build in constructor for comparing things in the Comparator class:

asStream(folder.get_SubFolders())
  .sorted(Comparator.comparing(Folder::get_DateCreated ))
  .map(Folder::get_Name)
  .forEach(System.out::println);

I hope that this post will motivate you to embrace the Java 8+ features in your IBM P8 Content Manager projects. The general idea is that you can simplify your code and take advantage of the new build in functionality. If you get stuck, then the Internet is full of examples of doing it the “New” way.

Leave a Comment