There are a few things not so very nice with the way of implementing a manager called "The New World Order". Before you all give up muttering something about things changing all the time I want take this opportunity and say that it is not so easy for a bear of very little brain and I need a few iterations to get things decent. Furthermore I want to say that I am not forcing you to do your managers in a certain way and that there is nothing stopping you from doing your manager without Spring and all my fancy inventions -- of course you won't get recording, automagic job creation, translation from String to IFile and all that stuff , you will have to do it yourself, nevertheless if that is want you want I won't stop you.
Now for the list of things not optimal with "The new World Order".
- Most importantly. All the methods defined in the interface but not implemented in the manager. Yes those pesky "This manager method should not have been called"-ones.
- Ola raised the problem of calling multiple long running jobs parallel in one job and then wait for all of them to finish. Something I can definitely see would be useful when doing things like QSAR calculations on any computer with more than one core (basically that means any machine these days...).
So much for the background here comes the suggestion. First of all in order to get rid all the methods that we don't want to implement the manager will not implement the manager-interface -- no more XManager implements IXManager. When doing managers in this way the coupling between the manager and the interface is loose. The actual dispatching of methods would be done by a
MethodInterceptor which would catch all method calls on the manager and call the right method with the right arguments.
Basically I see the need for three different sort of methods when dealing with long running operations. I will show with 2 examples. First a method receiving a BioObject and returning another BioObject.
Methods on the interface
public IMolecule
generate3dCoordinates( IMolecule molecule );
public void generate3dCoordinates( IMolecule molecule,
BioclipseUIJob uiJob );
public BioclipseJob
generate3dCoordinates( IMolecule molecule,
String jobName );
First we have the standard method that will be used from JavaScript and that will be run in the gui thread (freeze Bioclipse) if run from Java. Next is another old friend but in a slightly different appearance. This is the method used when writing actions in context menus for example. It is void (we can't hang around waiting for the result) and creates a Job. The code updating the GUI afterwards is given through the BioclipseUIJob -- in the method named runInUI. Finally we have a new friend. This method returns a job. This method is meant to be used from other manager methods. For example imagine a method in some fancy Manager. Our method needs to generate 3d coordinates for a bunch of molecules and than do some fancy calculations on all of them. The idea is that you can write it a little bit like this:
BioclipseJob job1
= cdk.generate3dCoordinates(mol1, "first job");
BioclipseJob job2
= cdk.generate3dCoordinates(mol2, "second job");
job1.join();
job2.join();
IMolecule mol1With3d = job1.getResult();
IMolecule mol2With3d = job2.getResult();
So each cdk.generate3dCoordinates call will be a job of it's own. By the way the String jobName paramater must be there or the third method's signature will clash with the first one.
All this will be accomplished by one method on the actual manager implementation. It will look something like this:
Method in the Manager class
public IMolecule
generate3dCoordinates( IMolecule molecule,
IProgressMonitor monitor );
All the translation from the methods declared in the interface to this method will be done by the MethodInterceptor which of course comes in one flavor for Java and one for JavaScript.
Let's look at one more example. This one is for working with files and contains the String -> IFile conversion.
Methods on the interface
public IMolecule loadMolecule( String path );
public void loadMolecule( IFile file,
BioclipseUIJob uiJob );
public BioclipseJob loadMolecule( IFile file,
String jobName );
This is basically business as usual by now. The String -> IFile conversion would also be done by the very same MethodInterceptor.
Method in the Manager class
public IMolecule loadMolecule( IFile file,
IProgressMonitor monitor );
So, what does this solution lack? :)