Change Preprocessors

Change preprocessors are server-side, user-implemented action handlers that change new or updated source objects before they are persisted to the Content Engine database. You associate a change preprocessor handler with a class definition. When a client saves an object of that class, the associated handler is triggered.

Change preprocessors allow source object modifications that are difficult or impossible to achieve with asynchronous or synchronous event action handlers. For example, a change preprocessor must be used to alter settable-only-on-create (SOOC) properties because SOOC properties cannot be changed after they are persisted. For feature comparisons between change preprocessors and event action handlers, see Action Handlers: Restrictions and Best Practices.

Change preprocessors have these characteristics:

  • The source object in a create, update, or delete server request is passed to a change preprocessor handler. The source object includes a properties collection and the set of pending actions.
  • You can implement a change preprocessor handler as a Java or JavaScript component. A change preprocessor that is implemented with Java can be placed in a code module, and can coexist in the same code module with other action handler types: event action, lifecycle action, and document classifier. For more information, see Deploying Java Action Handlers.
  • You can set one or more change preprocessors on a subscribable class definition, such as Document. For more information, see Setup Requirements.
  • A change preprocessor set on a class is applied recursively to subclasses in the class hierarchy. For example, if you set a change preprocessor on the Document class, it is also applied logically to the subclasses of the Document class. All enabled preprocessors that are associated with the source object's class hierarchy are loaded and called per change request, regardless of whether the change is for create, update, or delete.

    If the same preprocessor is referenced multiple times within a hierarchy, the preprocessor nearest the root of the hierarchy is started and all others are silently skipped. For more information, see Change preprocessor definitions.

  • A change preprocessor runs synchronously, so an exception rolls back the entire transaction.
  • If auditing is enabled, the audit log entry shows the changes that are made by change preprocessors. Change preprocessors are started before audit processing.
  • Unless disabled, change preprocessors are started unconditionally.
  • Changes that are made within a preprocessor can be persisted only if the request's starting user has the required permissions and if property constraints are not violated.

Implementation Guidelines

You implement the following method in the ChangePreprocessor interface:

boolean preprocessObjectChange(com.filenet.api.core.IndependentlyPersistableObject sourceObj)

In implementing this method, consider the following points:

  • You can retrieve the source object's pending actions array to perform conditional processing. A PendingAction object represents an intended change to the source object submitted by the client, which has not yet been performed by the server, such as a move content, update, or check-out action. By iterating the pending action array, you can control when the change preprocessor updates source object properties based on the actions that are submitted by the client. For a code example, see Creating a Change Preprocessor Handler.
  • You can retrieve the source object's property collection. The properties collection reflects the current state of the source object, along with any yet-to-be-persisted changes from the client.

    For creation requests to the server, the property collection is sparse; it contains only client-provided property values, any default values associated with properties not set by the client, and a few other properties that are determined by the object type.

    On update and delete requests to the server, the collection contains all properties that are currently defined on the object that is merged with those properties that are modified by the client.

    Because a change preprocessor handler runs regardless of the type of request to the server (create, update, delete), you cannot rely on all the properties being available in the source object's properties collection. Therefore, before you attempt to retrieve a property, it is recommended that a change preprocessor implementation call the IsPropertyPresent method to verify that the property is in the collection.

  • A side effect of a check-out on a current version is that a reservation object gets passed as a source object. In this case, the properties collection that is passed to the preprocessor includes any reservation properties that are submitted with the action, plus any copy-to-reservation properties from the originating source object. Therefore, a property definition with a CopytoReservation property set to false prevents a property instance from being copied to a reservation object's collection. For example, the MimeType property cannot be copied to the collection because of property definition constraints.
  • If a preprocessor changes the properties collection, return true to persist the collection to the server. Otherwise, if false is returned, the changes to the properties collection are lost (not persisted).
  • If a chain of preprocessors runs recursively in the class hierarchy, the preprocessors in the chain can see the property updates applied from the previously started preprocessors that returned true. The properties collection is not persisted until after all preprocessors are started.

Allowed Operations

  • You can implement updates to the source object's properties collection. An implementation can use fetchProperty to perform conditional processing based on property values of object-valued properties (OVPs).
  • You can remove properties from a collection. Note that you must remove fabricated properties; that is, properties that are not defined in a class definition, but have meaning only between a client and a preprocessor. If you do not remove fabricated properties, the Content Engine throws an exception.
  • Because change preprocessors are started before pending action processing, you can retrieve the source object's pending actions array.

Disallowed Operations

You cannot start the following operations, which adversely affect the source object's persistence:

  • Methods of IndependentlyPersistableObject that modify the object, like fetchProperties(), checkout(), save(), refresh(), addPendingAction(), clearPendingActions(), delete(), and setUpdateSequenceNumber().
  • Content access methods, like setCaptureSource() and accessContentStream().

Setup Requirements

To set up a change preprocessor:

  1. Implement the ChangePreprocessor interface.
  2. Create a CmChangePreprocessorAction object. This object contains a property for setting the implemented ChangePreprocessor interface. It also includes an IsEnabled property, allowing an administrator to disable a preprocessor at the system scope, no matter where it is referenced in the class hierarchies.
  3. Create a CmChangePreprocessorDefinition object. This object contains a property for setting the implemented ChangePreprocessorAction object. It also includes an IsEnabled property, allowing an administrator to disable a preprocessor at the class scope.
  4. Create a CmChangePreprocessorDefinitionList object and add the CmChangePreprocessorDefinition object to it.
  5. Get the SubscribableClassDefinition object that represents the class definition on which you want to set the change preprocessor.
  6. Set CmChangePreprocessorDefinitionList on the SubscribableClassDefinition object and save it.

You can get all CmChangePreprocessorAction objects with the ObjectStore.CmChangePreprocessorActions property. You can get all CmChangePreprocessorDefinition objects with the SubscribableClassDefinition.ChangePreprocessorDefinitions property.

For code examples of setup and retrieval operations, see Working with Change Preprocessors.