Wednesday, April 29, 2009

"Improving interface design" presentation

By the way of a colleague, a thought inspiring presentation on the creation of user interfaces.

This one quote stuck with me above everything else:

"I've been amazed at how often those outside the discipline of design assume that what designers do is decoration. Good design is problem solving."

Friday, April 10, 2009

AspectJ for Java logging: Serviceability without the clutter - part 6

Just realized I was missing the join point for constructors in the code. I also noticed the "getArgs" method in the "thisJoinPoint" object, which simplified the "methodError" point cut.

See the changes in red and the whole "Logging.aj" aspect as it stands today:

package my.project.aspects;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Aspect for Java logging throughout the code base.
*/
public aspect Logging pertypewithin(my..* && !Exception+) {

    private static Logger trace = Logger.getLogger("trace.my.project");

   /*
     * Pointcuts
     */
   
 
/**
* Initialization of all classes in the project.
*/
pointcut classInitializer() :
staticinitialization(my.project..*) &&
!within(Logging);

    /**

     * Execution body for all methods.
     */
    pointcut method():
(
execution
(my.project..*.new(..)) ||
        execution(* my
.project..*.*(..))
)

  &&
!within(my.project.D.*)
&&
!within(Logging);

    /**
     * Exception handling blocks inside all methods.
     */
    pointcut methodError():
        handler(handler(Throwable+) &&
!handler(InterruptedException+) &&

        within(my.project..*.*) &&
        !within(my.project.D.*) &&
        !within(Logging);

    /*
     * Join points
     */

    /**
     * After the initialization for all classes in this project.
     */
after(): classInitializer() {
String classname = thisJoinPointStaticPart.getSourceLocation().getWithinType().getName();
trace = Logger.getLogger("trace." + classname);
}

    /**
     * Entry trace statements for all methods.
     */
    before(): method() {
        if (trace.isLoggable(Level.FINER)) {
            trace.entering(
thisJoinPointStaticPart.getSourceLocation().getWithinType().getName(),

                    thisJoinPointStaticPart.getSignature().toString(),
                    thisJoinPoint.getArgs());
        }
    }

    /**
     * Exit trace statements for all methods.
     */
    after() returning (Object result): method() {
        if (trace.isLoggable(Level.FINER)) {
            trace.exiting(
thisJoinPointStaticPart
.getSourceLocation().getWithinType().getName(),

                    thisJoinPointStaticPart.getSignature().toString(),
                    result);
        }
    }

    /**
     * Exception handling blocks inside all methods.
     */
    before(): methodError() {
        if (trace.isLoggable(Level.FINER)) {
Object target = thisJoinPoint.getArgs()[0];
            trace.logp(Level.SEVERE,
thisJoinPointStaticPart.getSourceLocation().getWithinType().getName(),
                    thisJoinPointStaticPart.getSignature().toLongString(),
                    "Caught exception: " + target.getClass().toString(),
(Throwable)target);
        }
    }
 
}

Tuesday, April 7, 2009

AspectJ for Java Logging: Individual tracing control per Java package - Part 5

In "AspectJ for Java logging: Serviceability without the clutter - part 2" I had some difficulty in assigning a different trace handler for each class, which severely limited the application of the "Logging" aspect on larger programs. After all, it does not make sense to enable verbose trace on method entry/exit for all modules when debugging a single module.

A few minutes ago, some more reading solved the problem: one can use the "pertypewithin" aspect declaration, like this:

public aspect Logging pertypewithin(my.project..* && !Exception+){

/**
* Trace handler for each type.
*/
private static Logger trace = null;

/**
* Initialization of all classes in the project.
*/
pointcut projectClassInitializer() :
staticinitialization(my.project..*) &&
!within(Logging);

/**
* After the initialization of all classes in this project.
*/
after(): projectClassInitializer() {
String classname = thisJoinPointStaticPart.getSourceLocation().getWithinType().getName();
trace = Logger.getLogger("trace." + classname);
}

...

}


Now, the pointcut "projectClassInitializer" will pick out the static declaration of all Java classes within the project. Exceptions declared in the project are left out, as I do not see usefulness in instrumenting such basic classes, but that is a matter of preference.



The "after" advice will guarantee that the "trace" handler is initialized at the end of the static initialization for each class, using a handle named "trace.<classname>".



With this arrangement, it is now possible to configure different tracing levels within the logging.properties file for your java application, setting a different level for an entire package or for a single class, like this:




handlers = java.util.logging.ConsoleHandler
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

trace.my.level = INFO
trace.com.ibm.project.module1.level = INFO
trace.com.ibm.project.module2.level = FINEST
trace.com.ibm.project.module2.ClassA.level = FINER
...



-----

Friday, April 3, 2009

AspectJ for Java logging: Serviceability without the clutter - Instrumenting a 3rd party library - part 4

Another common serviceability problem while assembling libraries from multiple sources is that sometimes a reused library may use a difference serviceability framework, or even worse, not have any serviceability at all.

In the previous entries I covered techniques to instrument your own source code and source code from a different contributor. Now it is time to cover a technique to cover 3rd party libraries.

With AspectJ, this is a simple task accomplished with the AspectJ compiler: ajc. The compiler parameters are covered in the ajc page of the AspectJ developer's guide, but I suspect the majority of the people building Java code will resort to an Ant script. AspectJ has an Ant task called iajc, from where you can execute the same commands.

----

Compiling your aspects

The first step is, of course, to compile the serviceability aspects covered in the previous entries.

<iajc destdir="${dir.build.classes}" classpathref="class.path" deprecation="${javac.deprecation}">
<sourceroots>
<pathelement location="${dir.src}"/>
<pathelement location="${aspects.path}"/>
</sourceroots>
</iajc>




where "dir.src" is the directory where the project source code is located and "aspects.path" is the source directory where the aspects are located





----





Instrumenting a 3rd party library





The Ant taks has to be slightly modified to reflect a JAR file as the type of input and output, like this:








<iajc outJar="${dir.build.lib}/3rdparty.jar" classpathref="class.path" deprecation="${javac.deprecation}">
  <injars>
<pathelement location="${3rdparth.installdir}/libs/3rdparty.jar"/>
</injars>
<sourceroots>
<pathelement location="${aspects.path}"/>
</sourceroots>
</iajc>


----





And you are done! If both the JSR-47 and the Log4J aspects are in place, not only your new "3rdparty.jar" file will be instrumented with serviceability trace statements, it will also replace all extraneous Log4J calls with calls to their equivalent in JSR-47.





That is a very good result, considering that the resulting application assembled from multiple sources and libraries will benefit from these desirable serviceability traits:





  1. Consistent tracing, with trace entries for all the method entry and exit points and for all catch blocks


  2. Consistent trace control, with a single JSR-47 logging.properties file for all components


  3. Consistent output, with all modules directing their tracing output to the same file.