ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Learning Command Objects and RMI
Pages: 1, 2, 3, 4

Implementing our Translate Calls Using Method Objects

Now that we have our command object framework in place, let's revisit the translate code. Here's the new version of the ActionListener attached to the Translate Word Now button.



private class TranslationListener implements ActionListener {
  public void actionPerformed(ActionEvent actionEvent) {
    String resultText = "";
    Translator translator = _translatorPanel.getTranslator();
    Word word = _wordPanel.getWord();
    Language targetLanguage = _translatorPanel.getTargetLanguage();
    TranslateWord translateMethod = new TranslateWord(translator, word, targetLanguage);
    try {
      Word result = (Word) translateMethod.makeCall();
      resultText = result.toString();
    }
    catch (CouldNotTranslateException couldNotTranslateException) {
      resultText = COULD_NOT_TRANSLATE_STRING;
    }
    catch (Exception e) {
      resultText = e.toString();
    }
    finally {
      _resultsPanel.setText(resultText);
    }
  }
}

This is actually pretty similar to the code we used in the very first implementation. The only difference is that instead of calling the translate method directly, we create an instance of TranslateWord and call its makeCall method.

Here's the source for TranslateWord:

import java.rmi.*;
import java.rmi.server.*;

public class TranslateWord extends AbstractRemoteMethodCall {

  private Translator _translator;
  private Word _sourceWord;
  private Language _targetLanguage;

  public TranslateWord(Translator translator, Word sourceWord, Language targetLanguage) {
    _translator = translator;
    _sourceWord = sourceWord;
    _targetLanguage = targetLanguage;
  }

  protected Remote getRemoteObject() throws ServerUnavailable {
    return (Remote) _translator;
  }

  protected Object performRemoteCall(Remote remoteObject) throws RemoteException, Exception {
    Translator translator = (Translator) remoteObject;
    return translator.translate(_sourceWord, _targetLanguage);
  }
}

Summary and Roadmap

In this article, we've discussed the basics of using command objects. We've built an abstract base class for our command objects, and then implemented the remote calls for the Translator application by extending the base class. If we were to perform a cost-benefit analysis now, we'd see something like the following:

Pro

  • Encapsulation is good.The encapsulating method calls in separate objects, which makes the main program logic easier to read. ClientFrame is easy-to-read code and all the details of making the remote call have been placed in a separate location.

  • Difficult logic is implemented once, in the framework. The retry logic is implemented once, in an abstract base class, and is correct.

  • The client code is simple. The code required to create a new subclass of AbstractRemoteMethodCall is almost trivial -- it's both easy to write and easy to see (at a glance) that it's correct.

  • The framework provides hooks. We have some very nice hooks for using different retry strategies based on context. We also have some very nice hooks for inserting logging functionality.

Con

  • Indirection is confusing. Extra classes which encapsulate requests and the attendant level of indirection can be confusing. For small applications, using command objects feels like overkill.

  • Too much code. We haven't actually cut down the amount of code we need to write from the long 26-line while loop. The new code, while simpler, is just as lengthy.

  • It's an incomplete framework. Passing the stubs into the command objects feels strange -- surely the lookup code belongs inside the command object and not inside the object that simply wants to make the remote call.

  • We lost some type safety. The signature of makeCall -- returning instances of Object and throwing Exception -- is a violation of good programming practices. We've lost a fair amount of type safety here.

Opinions can vary. But I think that, even at this point, the pros significantly outweigh the cons.

Related Reading

Java RMIJava RMI
By William Grosso
Table of Contents
Index
Sample Chapter
Full Description

In the next article in this series, we'll discuss the third con, the fact that the framework is incomplete, in detail. We'll discuss why and how to build a local cache of stubs, and show how using command objects makes implementing a stub cache much cleaner. As part of this, we'll move all of the code that interacts with the RMI registry into the command objects (more precisely, we'll move the code that interacts with the RMI registry into an new abstract base class which extends AbstractRemoteMethodCall).

And in the final article of this series, we'll discuss the newly defined generics extension to Java and show how it partially addresses the last con by allowing us to return strongly typed values (instead of instances of Object).

William Grosso is a coauthor of Java Enterprise Best Practices.


Return to ONJava.com.