Sunday, October 31, 2010

Maven Multi-module Assembly Building

My first attempt at getting a multi-module maven assembly to work gave me some difficulty. I finally figured it out though and wish to share the result of my thrashing.

To cut to the chase, I found that to get the assembly to build properly and pick up all the latest dependencies you need to make sure that the assembly module is not a parent module of any of the other modules upon which the assembly depends.

The reason for this is that maven builds parent modules first before building any of the children modules. This means that if an assembly module is a parent module then it will be built before any of the submodules are built. This means that your assembly can not pick up any of the newly built modules that are below it. Either your assembly will fail (if you have never built it before) or the assembly will include old submodules from the previous build.

I found that a structure which puts the assembly module on a different branch of the multi-module tree works best. Something like the following worked for me:

   +-- /assembly
   +-- /module
     +-- /submodule1
     +-- /submodule2

Package-private Access won't work with Documentum BOF

If you are putting together several Documentum BOF modules such as TBOs and Aspects and they are located in the same java package you may be tempted to use Java package-private protections to allow shared access to methods and data between the modules without exposing the methods or data to outside code.

With Documentum BOF, however, you can not do this. The reason is that each TBO or Aspect gets their own private classloader. Even though the name of the package may be the same for the two modules and you might expect that they can share package private access, the reality is that since the packages are in two different class loaders they are not in fact the same package and therefore Java rightfully prohibits the access.

This means that you can't use package-private access for BOF TBOs and Aspects. For similar reasons you also can't rely upon class static data.

Need to quote DQL UNIQUE keyword

While using Documentum DQL to create a new type and index I came across a problem that was not particularly obvious. I figured I'd document it just in case others had the same problem.

The problem has to do with the DQL "unique" keyword. When creating an index using DQL the documentation says to use a command something like the following:

EXECUTE MAKE_INDEX WITH TYPE_NAME='mytype',ATTRIBUTE='myattribute',unique=true

I found, however, that on the version of Content Server I was using that this command did not work. After some amount of research I found that there is a bug introduced into the DQL parser that treats the "UNIQUE" token as a special keyword. This special treatment messes up the parsing the of MAKE_INDEX command. In order to work around the problem you can quote the UNIQUE keyword. This gets the token through the parser so that everything works as expected. The new command is as follows:

EXECUTE MAKE_INDEX WITH TYPE_NAME='mytype',ATTRIBUTE='myattribute',"unique"=true

Thursday, September 30, 2010

Protecting against LinkageErrors from DFC

Unfortunately I've discovered the hard way that DFC can throw more than just DfException and RuntimeException. It turns out that DFC can also generate nasty throwables like LinkageError. The problem with throwables like LinkageError is that the catch clauses people commonly put in there code to catch and handle unexpected conditions generally do not catch LinkageError because it is derived from Error and is not derived from Exception.

The reason DFC can throw LinkageError is because of its BOF activities. The dynamic classloading related to BOF can throw these errors when there are configuration problems with a particular BOF module.

To protect against occurances you need to add a "catch" clause for Throwable like this:
        IDfFolder object = (IDfFolder) session.newObject(XdsxFolderType.TYPE_NAME);
    catch (DfException e)
        // Do something with this exception
    catch (Throwable e) // Because DFC can generate a couple nasty "Error" throwables
        throw new RuntimeException(e);

Diagnosing DFC Configuration Problems

One common problem when trying to diagnose DFC configuration problems is determining where exactly your DFC configuration is coming from. The DFC configuration files likg and are located through the classpath. This provides a lot of power for configuring DFC in various different environments (like WAR files and EAR files). It is a double edged sword though. If your classpath is not quite set up right then you can often find the wrong DFC configuration.

There is a system property that you can set to help diagnose these kinds of problems. The property is "dfc.diagnose_config". If you add this system property to the command line of your java invocation then DFC will display the name of the configuration files that it is using.

For example:

   java -Ddfc.diagnose_config ...

The output will include something like the following:

   Reading DFC configuration from "file:/C:/configuration/"
   Reading log4j configuration from "file:/C:/configuration/"
   Reading dbor configuration from "file:/C:/configuration/"