The Registry Pattern

eXtreme Programming Markup Language (XPML) uses several XML documents that are interrelated. For example, releases refer to iterations, which refer to user stories, which might refer to use cases. These objects are referenced by name in the XML documents, and any code that deals with them needs to translate these names into real object references.

This is the situation that the Registry Pattern describes:

Objects need to contact another object, knowing only the object’s name or the name of the service it provides, but not how to contact it. Provide a service that takes the name of an object, service or role and returns a remote proxy that encapsulates the knowledge of how to contact the named object.

It’s the same basic publish/find model that forms the basis of a Service Oriented Architecture (SOA) and for the services layer in OSGi.

In XP Studio, the named objects of interest are the planning objects, e.g. releases, iterations, and such:

public interface PlanningObject {

  /**
   * @return The object's name
   */
  String getName();

  /**
   * Set the object's name.
   * @param name The name to set
   */
  void setName(String name);

  // ...
}

Any code that needs to reference such a planning object, can use the registry:

public class Registry {

  private static Registry instance;

  private final Map registry = new HashMap();

  public static synchronized Registry getInstance() {
    if (instance == null) {
      instance = new Registry();
    }
    return instance;
  }

  public synchronized Reference getReference(
      final String name) {
    final Reference result;
    if (isRegistered(name)) {
      result = registry.get(name);
    } else {
      result = new Reference(name);
      registry.put(name, result);
    }
    return result;
  }

  private boolean isRegistered(final String name) {
    return registry.containsKey(name);
  }

  public synchronized void register(
      final PlanningObject object) {
    final Reference reference = getReference(
        object.getName());
    if (!reference.hasObject() 
        || reference.getObject() != object) {
      reference.setObject(object);
    }
  }

  public synchronized void unregister(
      final PlanningObject object) {
    if (isRegistered(object.getName())) {
      final Reference reference = getReference(
          object.getName());
      if (reference.hasObject()) {
        reference.setObject(null);
      }
    }
  }

}

Note that the actual code uses Java5 generics, but WordPress’ source code formatter can’t handle that.

The planning objects use the registry to register themselves:

public class PlanningObjectImpl 
    implements PlanningObject {

  private String name = "";

  public PlanningObjectImpl(final String name) {
    setName(name);
  }

  public String getName() {
    return name;
  }

  public final void setName(final String name) {
    if (!this.name.equals(name)) {
      Registry.getInstance().unregister(this);
      this.name = name;
      Registry.getInstance().register(this);
    }
  }

  // ...
}

Now any client code can get references to the planning objects:

public class Reference {

  private PlanningObject object;
  private final String name;

  public Reference(final String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public boolean hasObject() {
    return object != null;
  }

  public PlanningObject getObject() {
    return object;
  }

  public void setObject(final PlanningObject object) {
    this.object = object;
  }

}

One example of using references is with user stories, which may depend on other user stories:

public class UserStoryImpl extends PlanningObjectImpl 
    implements UserStory {

  private final Set dependsOn = new HashSet();

  public UserStoryImpl(final String name) {
    super(name);
  }

  public void addDependsOn(final String userStoryName) {
    dependsOn.add(Registry.getInstance().getReference(
        userStoryName));
  }

  public Set getDependsOn() {
    final Set result = new HashSet();
    for (final Reference reference : dependsOn) {
      if (reference.hasObject()) {
        result.add((UserStory) reference.getObject());
      }
    }
    return result;
  }

  // ...

}

That’s the basic registry pattern implementation.

The actual code in XP Studio employs some enhancements. One of them is the use of namespaces so that objects in different projects can use the same name.

Another neat trick is to override the equals() method of both PlanningObjectImpl and Reference to make sure that references and the objects they refer to are regarded as the same, which can greatly simplify some code.

Advertisement

3 thoughts on “The Registry Pattern

  1. Can you elaborate why you need to use a Reference class between the PlanningObject and your repository? It seems to me you could put your PlanningObject right in the HashMap, and still be able to retrieve it by name. Also, letting the PlanningObject evict another object from registry and plant itself in its place as you set it’s name looks like a bad practice. Have a factory that will assemble your services and put them in the registry instead

    1. Luke,

      Thank you for your comment.

      The Reference is a level of indirection for handling timing issues. For instance, I can get a reference to an object before the object is published in the registry. In the example of XPML, this happens when you load e.g. an iteration before you load the user stories in it. The Reference also makes it possible to write robust code that doesn’t throw NullPointerException when the referenced object is unavailable.

      As for replacing another object, there are use cases where this is required. You may not have such a use case, and that’s fine. The code as shown is just one possible implementation of the Registry Pattern. As always, you should look carefully at your own situation, and use code that behaves well in it. This implementation is just one example that can serve as inspiration.

      Happy coding!

Please Join the Discussion

Please log in using one of these methods to post your comment:

WordPress.com Logo

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

Facebook photo

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

Connecting to %s