OSID 2.0 Design Patterns
Implementation Instrumentation
Tom Coppeto
OnTapSolutions
11 April 2005

At first I had a difficult time with the OSID Exception handling. Exceptions with useful error messages discarded and replaced with OPERATION_FAILED at the Interface.

Too many of us wrote programs that gathered configuration information in the top of the program and moved it downward while simultaneously collecting status messages and returning them back upward. The OSID then begins to look like a firewall preventing us from reaching our destiny in the programming world of the vt100.

In the last article, Implementation Configuration, configuration was loaded and retrieved entirely below the Interface boundary. So once again, the question is not if the Exceptions can be accessed, but where they can be accessed. And as always, the answer is below the Interface.

Often the phrase from the Interface zealots is heard, what happens inside the Implementation is none of your business, and this is always a scary concept. Actually, what is intended is none of the Application's business. That doesn't mean that system managers, application developers and users can't find out what is going on down there. They just can't do it through the Application code and that's different.

In this article, we're going to examine a simple logging mechanism used within Implementations to capture diagnostic information the using Logging OSID.

Yes, Logging. Some might look at the Logging OSID as a less useful alternative to Logs4j and others might be turned off because they don't want a log file. It's still the right answer.

There's no law that says an Implementation of the Logging OSID must write to a log file. You can do whatever you like inside the Implementation. Send an alert. Popup a window. Order pizza. Write to stderr. All or none of the above.

The OsidManager

The first problem at hand is instantiating the LoggingManager. The Three Bears rule applies here. Instantiating it for every call is too much and having a single instance stashed in some static class is too little. Different Implementations may require different Logging Implementations. One Logging Implementation for every OsidManager instance feels about right. But we can be a little clever about it.

Once again, the OsidManager Implementation can be exploited to keep the subclasses a bit cleaner. The subclassed manager can invoke getLogger() at initialization time.


    protected OsidLogger getLogger() {
 
        String impl    = getConfiguration("logging_osid");
        String logName = getConfiguration("logging_log");

        OsidLogger ol  = new OsidLogger(impl, logName);

        String level   = getConfiguration("logging_filter");
        if (level != null) {
            ol.setFilter(level);
        }       
        return (ol);
    }

Listing 1: a new getLogger() method inside OsidManager (requires OsidManager with cascading properties)

getLogger() primarily retrieves some properties and passes the work of loading the Logging Implementation to a static class, OsidLogger. The feature of accessing the properties inside OsidManagerWithCascadingProperties is that the Logging Configuration can be set globally, or overridden on an OSID or Application basis. Want to just see trace output for a given AuthenticationManager? No problem.

Using the Logger

getLogger() needs to be called from somewhere. In the previous article, an initialize() method was created inside the manager which is intended to only be called by it's own assignConfiguration() method. As good a a place as any to get the log rolling.


    public class AuthenticationManager 
        extends OsidManagerWithCascadingPropertiesAndLogging
        implements org.osid.authentication.AuthenticationManager {

        OsidLogger logger;

        protected void initialize() 
            throws org.osid.OsidException {
        
            logger = getLogger();
            logger.logDebug("initializing AuthenticationManager");
            ...
        }
        ...
    }

Listing 2: an example manager creating and using the logger

I tend to name my OsidManager Implementations with painfully descriptive names to indicate what functions they have. There's no rule that says new methods to perform a variety of tasks can't be created here. A given OSID Implementation is inherently tied to the OsidManager Implementation and packaged in the same jar file so no one expects interchangeability here. The new methods introduced are only accessed from within the class instance and is in itself an Implementation detail.

In most cases, there is a need to access the logger from outside the manager. As it turns out, this is a more general problem that requires a more general solution.

Code Listings
OsidManagerWithCascadingpropertiesAndLogging
OsidLogger