Chapter 16. Notification

Collects errors and other messages to report back to the caller.

image

I’ve carried out some operations that made significant changes to an object model. Now that I’m done, I want to check that the resulting model is valid. I can initiate a validation command; I want to know the answer as a simple Boolean, but if there are errors I want to know more. In particular, I want to know about all the errors rather than have the validation stop at the first error.

A Notification is an object that collects errors. When a validation check fails, it adds an error to the Notification. When the validation command finishes, it returns the Notification. I can then ask the Notification if everything was OK, and if not, delve into the errors.

16.1 How It Works

The basic form of Notification is a collection of errors. During the notified task, I need the ability to add an error to the notification. This can be as simple as adding an error message string, or it can be a more involved error object. When the task is done, the Notification goes back to the caller. The caller invokes a simple Boolean query method to see if all is well. If there are errors, it may interrogate the Notification further to display them.

The Notification usually needs to be available to several methods in the model. It can either be passed in an argument as a Collecting Parameter [Beck IP], or it can be stashed in a field if there’s an object that corresponds to the task at hand, such as a validator object.

The primary purpose of a Notification is to collect errors, but it’s sometimes useful to capture warnings and informational messages too. An error indicates the requested command has failed; a warning occurs for something that doesn’t fail but is still a matter of potential concern to the caller. An informational message is just some potentially handy information.

In many ways, a Notification is an object acting like a log file, so many of the features commonly found in logging can be useful here.

16.2 When to Use It

A Notification is useful whenever there is a complicated operation that may trigger multiple errors and you don’t want to fail at the first error. If you do want to fail at the first error, then you can simply throw an exception. A Notification allows you to store multiple exceptions to give the caller a fuller picture of what the request led to.

Notifications are particularly useful when a user interface initiates an operation at a lower layer. The lower layer should not try to interact with user interface directly, so a Notification makes an appropriate messenger.

16.3 A Very Simple Notification (C#)

Here’s a really simple Notification that I used for a couple of my book examples. All it does is store errors as strings.

image

Using a format string and parameters makes it a bit easier to use the notification to capture errors, as the client code doesn’t need to build the format string.

image

I provide a couple of Boolean methods for the caller to check if there are errors.

image

I also provide a method that checks and throws an exception if there are errors. Sometimes this fits the flow of usage better than using the Boolean check methods.

image

16.4 Parsing Notification (Java)

Here’s a different Notification that I use in the example for Foreign Code. It is a bit more involved than the C# above and also more specific, as it takes specific kinds of errors.

Since it’s part of an ANTLR parse, I put a Notification into the Embedment Helper of the generated parser.

image

public void run() {
  try {
   lexer = new AllocationLexer(new ANTLRReaderStream(input));
   parser = new AllocationParser(new CommonTokenStream(lexer));
   parser.helper = this;
   parser.allocationList();
  } catch (Exception e) {
   throw new RuntimeException("Unexpected exception in parse", e);
  }
  if (notification.hasErrors())
   throw new RuntimeException("Parse failed: " + notification);
 }

This particular Notification handles two specific error cases. The first of these is an exception thrown by the ANTLR system itself. In ANTLR, this is a recognition exception. ANTLR has default behavior for this, but I want to also capture the error in a Notification. I can do this by providing an implementation for an error reporting method in the members section of the grammar file.

image

The other case is an error during the parse that the Embedded Translation code recognizes. At one point, the grammar is looking for a list of products.

image

In the first case, I pass ANTLR’s recognition exception object to the Notification; in the second case I pass a token and an error message string—again, using the format string convention.

On the inside, the Notification has a list of errors—in this case, instead of a string, I use a more meaningful object.

image

I use a different kind of object for the two different cases. For ANTLR’s recognition exception, I use a simple wrapper.

image

As you can see, the superclass is only a marker to make the generics work. In time, I might add something to it, but for the moment a bare marker suffices.

For the second case, I assemble the incoming data into a different object.

image

By passing the token in, I’m able to provide better diagnostic information.

I provide the usual methods to detect if there are any errors and to print a report of errors if any crop up.

image

I think the most important point here is to build a Notification that makes the calling code as simple and compact as possible. Therefore, I pass all the relevant data to the Notification and let the Notification sort out how to compose error messages from this data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.231.15