Say Scheveningen

Entries categorized as ‘dfc’

A trap with aspects

September 4, 2009 · 1 Comment

Sometimes you want to write an aspect with behavior that is orthogonal to that in DfSysObject. Nothing wrong with that – we encourage it – but here’s the rub …

When DFC dynamically builds the Java class for an object to which your aspect is attached it dynamically builds an inheritance hierarchy with the TBO and its DFC superclasses as the supermost classes, and with each aspect subclassing each other and ultimately the TBO. DFC literally patches the superclass pointers in the byte code. You are going to subclass DfSysObject and its superclasses whether you want to or not.

Now if you are intending to write an aspect with orthogonal behavior you have to be really careful not to unintentionally override a DfSysObject (or superclass) method, which could have bizarre consequences. A more overt and terminal consequence arises if you unintentionally override a final method – you get the infamous java.lang.VerifyError, although it isn’t related to class loaders this time. An example of this is if you try to use a DfService implementation as an orthogonal aspect implementation (you can’t).

The best tip? Just subclass DfSysObject in your aspect primary class in the first place and the enforced runtime inheritance structure will be reflected at compile time.

Categories: bof · dfc

java.lang.VerifyError and the whole truth

February 23, 2009 · Leave a Comment

The BOF class loader diagrams I have published before contain a simplification that I had hoped to finesse, but reality seems to have caught up with me.

The whole truth is that the sandboxing BOF class loaders aren’t strictly parent last. Their behavior is:

  1. Java extension loader
  2. The BOF sandboxed loader
  3. The parent loader

The first item is important to avoid the sandboxing of Java runtime classes. This is the behavior that most app server web app class loaders observe.

But not WebSphere. In PARENT_LAST mode, WebSphere does strict sandboxing. Now if your web app includes an extension library (not recommended, but not that uncommon) WebSphere will load it from the web app class loader in preference to the extension class loader. In the absence of BOF, this wouldn’t matter much because it would be loaded once and only once. But along comes a dynamically loaded BOF module which causes it to be loaded by the extension class loader. Now the class is loaded in two loaders in the parent chain. This results in a VerifyError.

DFC accommodates this apparently intractable problem by having a preference – dfc.bof.classloader.enable_extension_loader_first – which is set to true by default. If you are using a PARENT_LAST WebSphere class loader with an extension library in the web app then you will have to set this to false and try your luck. This causes the first step to be skipped by the BOF sandboxing class loader. Better would be to remove the library from your web app altogether and rely on the extension loader.

How did you get an extension library in your web app? Well across Java releases various packages have migrated into the system extensions. Older web apps legitimately packaged the library du jour and only after a Java upgrade does this behavior potentially manifest. Java 5 added a number of XML related packages, for example.

Categories: bof · dfc

Debugging BOF2 modules in your IDE

September 19, 2008 · 1 Comment

In BOF 2, the class loading is performed under control of DFC using a custom class loader structure (see BOF class loaders). For IDE debugging purposes this can be a nuisance. To assist during development there is a feature built in to DFC that allows you to configure various modules to be loaded from your application class loader.

You define a properties file, say devbofregistry.properties, of the form …

my_type=type,com.myco.MyType
my_aspect=aspect,com.myco.MyAspect
com.myco.IMyModule=module,com.myco.MyModule
com.myco.IMyService=service,com.myco.MyService

and set a system property, dfc.development.bof.registry_file, to the full path of the file. Note that you have to install some version of the BOF module to the docbase before you try this – only then can you hijack the class loading mechanism.

Be aware that you are cheating though, and that this usage can mask packaging problems. The fact that a class is visible in your IDE does not mean it will be visible with proper BOF class loading. You might, for example, simply forget to include it in your implementation jar (missing from an ant file jar task perhaps).

Categories: bof · dfc

Attaching and detaching aspects

July 7, 2008 · Leave a Comment

The first thing you need to understand is that the Java object you get from IDfSession.getObject or IDfSession.newObject is not the actual persistent object – it is a proxy object (google Java dynamic proxies for more info). It looks like a regular old persistent object to you, but it isn’t.

Whenever you attach (or detach) an aspect you might end up changing the prototype of the persistent object. This would be the case if an aspect implemented an orthogonal interface. DFC will actually rebuild the class files (yes, the byte code) that relates to the type [+aspects] in question. This is an expensive operation and there are optimizations to minimize the number of times this is done.

Of course, your existing persistent object is already loaded from the old class definition and this can’t change, so you end up with a “stale” persistent object reference.

So, after attaching or detaching an aspect you must refetch the object immediately. The refetched object will implement any new interfaces and will not implement any removed interfaces. Any unsaved changes you made will be preserved. The sequence should be something like this …


if (obj instanceof IDfAspects) {
    (IDfAspects) obj).attachAspect(“foo”, null);
    obj = session.getObject(obj.getObjectId());
    ((IFoo) obj).foo();
}

The above code fragment is suitable when you are a regular client (eg. application code). However, if you are executing in the context of a TBO or aspect method on obj itself when you try to attach or detach the aspect, then you are executing on the “old” object that is about to become stale, and the new object has not been built yet, so getObject just returns the same old disappointing Java object. You then have to use callbacks. Callbacks are invoked just before the original entry point to the outermost TBO or aspect method invocation returns and have a kind of implicit getObject associated with them. You can think of them as delayed client code. Do not do getObject within a callback – the object reference your callback is given is the new, beautiful, predictable Java object. The code sequence would then look something like this …


this.attach/detachAspect(“foo”, myCallback); // myCallback invokes foo()
// You cannot use foo here – the Java object is not ready. Refetch won’t help either.

The callback implementation would look something like this …


void doPostAttach/Detach(IDfPersistentObject obj) {
    ((IFoo) obj).foo(); // ok, obj is fully cooked here
}

Also note that not all objects can have aspects attached. All sysobjects and its subclasses can, but most non-sysobjects don’t support aspects. Any object that does, however, will implement the IDfAspects interface (DFC sees to this automatically). A non-sysobject type would only support aspects if it were created with the DQL syntax …


alter type ... allow aspects

Categories: bof · dfc

BOF 101

July 3, 2008 · 2 Comments

BOF is a deployment mechanism we use for a number of different component types, like TBOs, SBOs, modules, aspects. This is how it works from a 20,000 ft view.

BOF modules are packaged using Composer into DARs (or docapps in the old days). They are deployed to a docbase. In general, with the exception of SBOs, they have docbase affinity (you might get a different implementation from a different docbase). SBOs are deployed to a global registry docbase and so have a single implementation.

Once deployed to the docbase, any DFC instance that communicates to that docbase will be sensitive to any changes made to the BOF module. If it detects a change (via an optimized polling strategy) it will download the new/updated module definition to its file system cache. You can find these caches in $DOCUMENTUM/cache/<release>/bof/<docbase>. In these directories you will find downloaded jars and other downloadable resources (the jar names are the object ids). You will also find a content.xml file which is a manifest. These caches can be deleted at will and will be automatically reconstructed as necessary by a running DFC instance. Zipping up this cache can be very useful collateral in debugging a BOF problem.

The BOF runtime (within DFC) runs entirely from the file system. Class loaders are constructed which point to the jar files on the file system, so there is no performance penalty in deploying to the docbase (except for the initial reference).

BOF supports hot deployment. If a DFC instance recognizes an updated BOF module it will download it and build a new class loader for that module which points to the updated jars. The next request for that module will use the new implementation. Any preexisting objects remain using the old implementation and will be aged out as they are garbage collected. This is great for updating an implementation, but you must never update a public interface or you will cause havoc (you would need to reload the web app and ensure application compatibility first).

The class loader and packaging implications of BOF will be addressed in a subsequent post.

Categories: bof · dfc