Inheritance versus Operation Providers

The Globus Toolkit 3 provides two implementation approaches:

The inheritance approach is the one used in the previous chapter. The class that implements the MathService interface, MathImpl, extends from a class called GridServiceImpl. Since GridServiceImpl contains all the basic functionality of a Grid Service, our MathImpl class simply has to provide all the operations specified in our particular portType (in our case, MathPortType):

The delegation approach, on the other hand, allows us to distribute the operations of our PortType in several classes. For example, it might make sense to separate the previous MathImpl into three classes: one for the arithmetic operations, one for the trigonometry operations, and one for the matrix operations. Each of these classes is called an operation provider.

Notice how these classes don't extend from any base class. They only have to implement an interface called OperationProvider. Of course, you might be wondering: If there is no base class to extend from, where do these classes get their 'basic Grid Service functionality'? Actually, GridServiceImpl is still present in this approach. The only difference is we're not forced to extend from it. We'll just need to tell the Grid Service container that GridServiceImpl will supply the basic functionality (this is done with the deployment descriptor; we'll see that in the next section).

So, why is the delegation approach better that the inheritance approach? First of all, imagine you want to write and deploy a Grid Service which has to extend from a Java class you already have. With the inheritance approach, you couldn't do this, because your Grid Service already has to extend from GridServiceImpl, And, of course, multiple inheritance is not allowed in Java (and, even if it were, multiple inheritance is considered very bad design).

Using the delegation approach, your provider class is free to extend from any class.

The delegation approach has other advantages, such as favoring more modular, uncoupled, and reusable designs (you can distribute all your operations into several operation providers, and then reuse providers in different Grid Services).

The only disadvantage of using the delegation approach is that it requires just a little bit more work and code than the inheritance approach. The deployment descriptor needs a couple of extra lines, and you need to implement the methods in the OperationProvider interface. However, this requires only a small (really small) amount of extra work.

Finally, take into account that in GT3 both approaches are not mutually exclusive. In other words, we could easily implement part of our portType in a class that extends from GridServiceImpl and then complete the implementation with operation providers. In fact, we'll see that this is a common technique in GT3, since the toolkit includes a lot of operation providers which we can directly 'plug into' our service to add functionality. For example, later on we'll see that to use notifications in a service we barely have to write any code ourselves. We simply have to 'plug in' the 'notifications operation provider' to add that functionality to our service.