DFC DfOperations Classes – Part 8

In this final post on DfOperation classes, I will touch on a few advanced topics.

IDfOperation Steps

If you want a little more control over the execution of an operation, you can execute each operation one step at a time and check for errors along the way.  To execute operations step-wise, replace the DfOperation.execute() method call with the following code snippet.

IDfList steps = OpObj.getSteps();
int stepCount = steps.getCount();
boolean result = true;
for(int i = 0; i < stepCount; i++) {
  IDfOperationStep step = (IDfOperationStep) steps.get(i);
  System.out.println("\t\texecuting step " + i + ". - " + step.getName());
  boolean stepResult = step.execute();

  if (!stepResult)
    result = false;
}

The result of this code for the DfCopyOperation is:

executing step 0. – copy_post_population
executing step 1. – copy_pre_processing
executing step 2. – copy_object_processing
executing step 3. – copy_container_processing
executing step 4. – copy_post_processing
executing step 5. – copy_cleanup

Now you are acquainted with the actual steps of the DfCopyOperation.

Operations Monitor

A cool thing you can do with all of the DfOperation classes is attach a monitor to them.  This is, for example, how Webtop displays the progress bar while objects are being copied/moved/imported/exported/deleted. Unfortunately, the DFC DfOperationMonitor class does not offer much to work with (the Webtop operations monitor class is much better). Here is an example of how to use monitoring in a DfOperation and an example of a class to monitor progress.

To enable monitoring, simply set the operation monitor to a DfOperationMonitor class, like this:

// setup monitor
CopyMonitor cm = new CopyMonitor();
copyOpObj.setOperationMonitor(cm);

Here is the CopyMonitor class:

	private static class CopyMonitor extends DfOperationMonitor implements IDfOperationMonitor {

		@Override
		public int getYesNoAnswer(IDfOperationError arg0) throws DfException {
			System.out.println("[ERROR: " + arg0.getMessage() + "] - continuing");
			return IDfOperationMonitor.YES;
		}

		@Override
		public int progressReport(IDfOperation opObj, int opPercentDone,
				IDfOperationStep opStepObj, int stepPercentDone, IDfOperationNode opNodeObj)
				throws DfException {

			IDfProperties props = opNodeObj.getPersistentProperties();
			String objName = props.getString("object_name");
			String objType = props.getString("r_object_type");

			System.out.println("[MONITOR: operation=" + opObj.getName() +
					           " operation%=" + opPercentDone +
					           " step=" + opStepObj.getName() +
					           " step%=" + stepPercentDone +
					           " object=" + objName + " (" + objType + ")");

			return IDfOperationMonitor.CONTINUE;
		}

		@Override
		public int reportError(IDfOperationError arg0) throws DfException {
			System.out.println("[ERROR: " + arg0.getMessage() + "] - aborting");
			return IDfOperationMonitor.ABORT;
		}
	}

The result of this code for the DfCopyOperation is a follows:

[MONITOR: operation=Copy operation%=4 step=copy_pre_processing step%=25 object=Nested (dm_folder)
[MONITOR: operation=Copy operation%=6 step=copy_pre_processing step%=37 object=Nested (dm_folder)
[MONITOR: operation=Copy operation%=8 step=copy_pre_processing step%=50 object=Document5 (dm_document)
[MONITOR: operation=Copy operation%=10 step=copy_pre_processing step%=62 object=Document1 (dm_document)
[MONITOR: operation=Copy operation%=12 step=copy_pre_processing step%=75 object=Document2 (dm_document)
[MONITOR: operation=Copy operation%=14 step=copy_pre_processing step%=87 object=Document3 (dm_document)
[MONITOR: operation=Copy operation%=16 step=copy_pre_processing step%=100 object=Document4 (dm_document)
[MONITOR: operation=Copy operation%=18 step=copy_pre_processing step%=112 object=VirtualDoc (dm_document)
[MONITOR: operation=Copy operation%=4 step=copy_object_processing step%=25 object=Document5 (dm_document)
[MONITOR: operation=Copy operation%=6 step=copy_object_processing step%=37 object=Document1 (dm_document)
. . .

I suspect this is not the output you expected from the CopyMonitor class. Look how the operation and step complete percents jump around. I included a better monitor class with the code archive mentioned at the end of this post.

Aborted Operations

Most operations can be rolled back after they complete, but before the operation object is destroyed, or if an error occurs during processing. This is a really handy feature to help clean up after an error, but also to implement the notion of “cancelling” an operation. The code below augments the error checking we have used previously to implement an abort() and roll back the operation.

// check for errors
if (!result) {
  IDfList errors = copyOpObj.getErrors();
    for (int i = 0; i < errors.getCount(); i++) {
      IDfOperationError err = (IDfOperationError) errors.get(i);
      System.out.println("Error in Copy with Abort operation: " + err.getErrorCode() + " - " + err.getMessage());
    }

    // process abort
    if (copyOpObj.canUndo()) {
      System.out.println("\t\taborting operation...");
      copyOpObj.abort();
    }
}

That’s all there is to it. The DfOperation class will take care of undoing all of the steps of the operation. Pretty cool, eh?

Wrap Up

In general, I like the DfOperation classes and use them whenever I can. As mentioned previously, there are some great benefits to using DfOperation classes instead of coding these operations yourself.  In addition to the benefits, I hope you have seen how easy they are to implement, and you get the bonus of having built in undo methods and monitoring classes.

As cool and useful as DfOperations are, there are a few shortcomings, in my opinion:

  • You cannot create and insert steps into an operation.  For example, I would like to add a step to the Copy operation so that before the copy is done, the operation checks a value in a registered table.
  • You cannot extend the existing operations.  I would love to extend the DfExportOperation class to do deep folder exports.
  • You cannot write your own DfOperation classes.  I think it would be useful to create some custom operations like synchronizing metadata with an external data source.

Finally, working examples of all of the operations I have presented in this series are available here.

Advertisements

About Scott
I have been implementing Documentum solutions since 1997. In 2005, I published a book about developing Documentum solutions for the Documentum Desktop Client (ISBN 0595339689). In 2010, I began this blog as a record of interesting and (hopefully) helpful bits of information related to Documentum, and as a creative outlet.

One Response to DFC DfOperations Classes – Part 8

  1. Pingback: DfOperations Sample Code « dm_misc: Miscellaneous Documentum Tidbits and Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: