Archive for the ‘Java’ Category.

Weak and Soft References in Java

Types of References in Java

Before I get to the point, let me introduce you a couple of classes we’ll count on when going through examples later.

The first one is Item:

package com.centuryminds.softreferences;

/**
 * An item
 */
class Item
{
  //class members
}

And here comes Group:

package com.centuryminds.softreferences;

import java.util.ArrayList;
import java.util.List;

/**
 * A group of {@link Item}
 */
public class Group<T extends Item>
{
  private final List<T> items = new ArrayList<T>();

  public void add(T item)
  {
    items.add(item);
  }

  // other methods
  // ...
}

Let’s start the ball rolling. This is the most common way to create a reference to an object from another one (okay, forget about the factories, IoC and such for a while):

Item item = new Item();

The item element is called a strong reference. Why is regarded as strong? A new well-kown player named Garbage Collector -GC from now on- comes up , which is responsible of taking care (i.e. freeing) of the memory resources. When an object Client, holding a reference to item:

A strong reference

decides to not use item anymore:

Not needed anymore

after an undetermined time, the GC might decide to dispose of the instance formerly referenced by item.

To illustrate a dime a dozen problem associated to strong references, let’s suppose we have an object Group, referencing a bunch of Item elements through its internal items list member.

Items in a Group

As we can see in the figure, there are a couple of external references to the Items. What happens when these references are not needed anymore and stop pointing at those Items?

No more external references

At this point in time, the logic of our application might require us to remove the references to the Items in our Group instance, since they are not used anymore. That’s a burden every now and then. Actually, what we are doing is duplicating efforts, since this should be the main responsibility of the GC.

WeakReferences

A WeakReference is a reference which does not prevent an object to be reclaimed by the Garbage Collector. A WeakReference allows you to pass the GC the buck when determining the reachability of an object for you.

A weak reference

Here is how a WeakReference is created:

package com.centuryminds.softreferences;

/**
 * Creating a WeakReference
 */
class A
{
  private final WeakReference<B> b = new WeakReference<B>(new B());

  public B getB()
  {
    return b.get();
  }
}

A small hint here: the method getB() might return null if there are no strong references to the internal reference b. As a matter of fact, the previous is an awful example, since the first call to getB() could return null in case the GC decided to reclaim b and release the memory assigned to it before that method call. Not good.

SoftReferences

Another far more interesting type of reference we may take advantage of is the SoftReference. In short, this type of reference is like a WeakReference, but tells the GC to not reclaim the wrapped object if there is enough free memory. In other words, if the the GC needs more free memory after reclaiming the objects reachable through strong and weak references, then it will reclaim the instances only reachable through soft references. This, as we will see, makes an excellent candidate for becoming a smart invalidation policy within a cache.

An all-dancing cache

We are going to build up a cache of objects using soft references. Motivation for a cache:

  1. There are some elements which are very expensive to retrieve
  2. Those elements are used frequently
  3. The number of such elements (or the number of the most frequently used) is limited

In our particular case, the expected behavior of our cache will be:

The objects stored in the cache will be discarded if they are referenced by the cache only AND more free memory is required.

The Garbage Collector will be in charge of that. The ball is in its court now.

A code snippet is worth a thousand words:

package com.centuryminds.softreferences;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;

/**
 * Generic cache based on SoftReference's
 */
public class Cache<T>
{
  private final Map<String, SoftReference<T>> cache = new HashMap<String, SoftReference<T>>();

  /**
   * Look an element up by its id
   */
  public T get(final String id)
  {
    T elem = null;

    if (cache.containsKey(id))
    {
      SoftReference<T> ref = cache.get(id);
      elem = ref.get();
    }

    // elem could value null here in two cases:
    // (1) it was not stored in the cache
    // (2) it was garbage collected
    if (elem == null)
    {
      elem = getElemFromExternalService(id);
      cache.put(id, new SoftReference<T>(elem));
    }

    return elem;
  }
}

This cache manages elements of unknown types at compile-time, which are retrieved by their ids through calls to getElemFromExternalService(id). This method may be a private member of the cache, a callback or whatever. The key point here is that the elements are stored as soft references. When an external entity asks the cache for an element, it is linked to it through a strong reference:

// returns the wrapped object
elem = ref.get();
...
// a strong reference for the callee
return elem;

Bear in mind this is vital to our purposes, since the existence of a strong reference whilst the object is being used will prevent it from being garbage-collected.

Extra goodies

  • WeakHashMap is a Map whose keys are stored using weak references. Refer to the Javadocs for further information.
  • A wrapped object by a WeakReference becoming rubbish does not imply that the WeakReference itself defuncts. We thus have to perform some kind of cleanup of those references. WeakReference has got a contructor which accepts a ReferenceQueue, which is used to track stale references to WeakReferences objects. Take a look at the Javadocs to get more information on how to use it.
  • There is another type reference named phantom reference, but it is not worth the hassle explaining it for the purposes of this post.
  • An open question: if WeakHashMap exists, what happened to SoftHashMap? I don’t want to make a mountain out of a molehill, but this class would be at least as useful as WeakHashMap, if not more.

Java static imports + Fluent interfaces + Builder pattern= DSL

After having written nothing for a long time I am back to talk about an interesting bunch of java features. I am talking about DSL in Java, not as clean and powerful as in Ruby but, I think, very interesting for Java developers.

Static import

So, let’s start with static import, a nice Java feature introduced in its 5th version. Until Java 5, we could only import classes for using in our code, so that, instead of using something as ugly as java.util.List list= new java.util.ArrayList() we could simplify by importing the List and ArrayList classes and omit the package class in the creation and usage of the objects.

But, what happens when we want to use static methods or properties of other classes?

MyFunnyClass.myMoreFunnierMethod(param)
MyFunnyClass.NotSoFunnyMethod(param)

Our code gets cluttered by retyping the class part, when this shouldn’t be necessary. Wouldn’t it be nice if we were able to express ‘I want to use the following static methods in my class, and then use them as methods defined in our class’ ?

We are lucky, Sun engineers introduced the static import feature in Java5. So how do we use it? This is a piece of cake:

import static mypackage.MyClass.interestingMethod
...
interestingMethod("Look ma, I don't need referencing to MyClass!")

or we can use wildcards instead:

import static mypackage.MyClass.*
...
interestingMethod("Look ma, I don't need referencing to MyClass!")
otherInterestingMethod("Look ma, I don't need referencing to MyClass!")

It doesn’t look very useful for what we usually code, and used incorrectly, can derive in a fist of method calls that we don’t know where they come from. But this feature is going to be crucial for DSLs design in Java…

Fluent interfaces

Fluent interfaces are a way of designing interfaces that allows us to chain method calls, making our code more readable. So, what does it looks like?

Without fluent interfaces:

Person person= new Person();
person.setName("John");
person.setSurname ("Smith");
person.setPet(new Dog("Charly"));
person.setClothingStyle(ClothingStyle.CASUAL);

With a fluent interface API:

Person person = new Person().name("John").surname("Smith").pet(new Dog("Charly")).clothingStyle(ClothingStyle.CASUAL)

Fluent interfaces make our code look much better.

Using chained methods is as easy as returning the object instance (this) at the end of each fluent method:

public class Person{
...
  public Person name(String name){
     this._name=name;
     return this;
  }
...
}

Fluent interfaces are compatible with having accessor methods (set* and get*) in our classes. Basically, the goal is to ease the API usage and uplift the readability/expressivity of our code.
You can get more information about fluent interfaces in Martin Fowler Blog.

Builder Pattern

The previous two features look very interesting, don’t they? And it seems that both of them can be used to improve our code readability, and actually they do. But there is a last feature that takes advantage of them , we are talking about the Builder Pattern.

Quoted from the Wikipedia:

The Builder Pattern is a software design pattern. The intention is to separate the construction of a complex object from its representation so that the same construction process can create different representations.

In short, we are going to have an object that facilitates the construction of …other objects! This implies that such a pattern is only useful when we design interfaces for objects that we are going to build up many times with different parameterization or to designing interfaces.

I am the sort of person that prefers an example over loads of paragraphs explaining it , hence go carefully through the following code:

package test;

import java.util.Calendar;
import static java.util.Calendar.* ;
import java.util.Date;

public final class TimeUtil {

    public static DateEx now() {
        return new DateEx(new Date());

    }

    public static DateEx tomorrow() {
        DateEx date = new DateEx(new Date());
        return date.add(days(1));
    }

    public static DateEx yesterday() {
        DateEx date = new DateEx(new Date());
        return date.subtract(days(1));
    }

    public static TimeUnit months(int n) {
        return new TimeUnit(MONTH, n);
    }

    public static TimeUnit years(int n) {
        return new TimeUnit(YEAR, n);
    }

    public static TimeUnit days(int n) {
        return new TimeUnit(DAY_OF_MONTH, n);
    }

    public static DateEx date(Date date) {
        return new DateEx(date);

    }

    private static final class TimeUnit {
        private final int type;
        private final int size;

        public TimeUnit(int type, int size) {
            this.type = type;
            this.size = size;
        }
    }

    public static final class DateEx {

        private final Calendar date;

        public DateEx(Date date) {

            this.date = Calendar.getInstance();
            this.date.setTime(date);
        }

        public Date toDate() {
            return date.getTime ();
        }

        public DateEx add(TimeUnit unit) {
            date.add(unit.type, unit.size);
            return this;

        }

        public DateEx subtract(TimeUnit unit) {
            date.add(unit.type, -unit.size);
            return this;

        }

        public DateEx clearTime() {
            date.set(HOUR_OF_DAY, 0);
            date.clear(MINUTE);
            date.clear (SECOND);
            date.clear(MILLISECOND);
            return this;

        }

        public DateEx firstDayOfMoth() {
            date.set(DAY_OF_MONTH, 1);
            return this;
        }

        public String toString() {
            return date.getTime().toString();

        }
    }
}

No worries, I am going to explain each line of code, or at least the more interesting ones:

import static java.util.Calendar.* ;

This rings a bell, I hope. In this case, importing Calendar static fields allows us to use them as:

            date.set(HOUR_OF_DAY, 0);
            date.clear(MINUTE);
            date.clear (SECOND);
            date.clear(MILLISECOND);

We are building a date builder, so we need another class especialized in the construction of java.util.Date objects. This DateEx inner class for:

    public static final class DateEx {
    ...
   }

The key point here is that DateEx is a construction utility that uses fluent interfaces, so that we can chain methods calls to DateEx objects like:

DateEx dateBuilder= new DateEx(new Date()).firstDayOfMonth().clearTime()

and finally get the date object:

Date date= dateBuilder.toDate()

This code seems alright, yet did you notice what an ugly code we are using to note “now” ? new DateEx(new Date()) ??? What the hell is this? If I want to express “now” I want something that actually does it, and “new DateEx(new Date..” doesn’t at all. Luckily, we might define convenient methods for that sort of things:

    public static DateEx now() {
        return new DateEx(new Date());

    }

Now, if we import the now static method in our class we can rewrite the previous code as:

DateEx dateBuilder= now().firstDayOfMonth().clearTime()

This is the kind of code that makes me happy (Yes, I know…). Look at it, and at first glance, you realize “hey, he is clearing the time part of the first day of the current month”.

Furthermore, we can add a couple of convenient methods to our new little API:

    public static DateEx tomorrow();
    public static DateEx yesterday();

There is also a TimeUnit inner class that allows us to express time units in order to perform time operations to our DateEx objects. For example, what if we wanted to get 1 month and 10 days before the current date? We can do it with our TimeUnit classes and static util methods as:

dateBuilder.subtract(months(1)).subtract(days(10));

Cooler than using our good ol’ Calendar friend.

What kind of things can we do with this example API?

package test;

import static test.TimeUtil.*;
import java.util.Date;

public class Example {
    public static void main(String [] params){

        Date date= new Date();
        System.out.println (date(date).add(years(1)));

        System.out.println(now().toDate());
        System.out.println(now().add(days(2)).add(months(1)).subtract(years(1)).clearTime().toDate());
        System.out.println(yesterday()+" - "+now()+" - "+tomorrow());
        System.out.println(now().clearTime().firstDayOfMoth());
    }
}

Neat, it is not perfect, a lot of brackets are needed which only mess the code up, but as I see it, we have improved the expressivity of our code. In any case, my advice is to learn a new language like Ruby or Groovy, it opens your mind and teaches you different ways of doing things.

On the other hand, Java 7 specification is going to define closures for the Java language, so in the future we are going to be able to do more interesting things!

You Need Code Reviews

Look at this code:

(within a while body)

...
if (log.isDebugEnabled()) log.debug("Parsing line " + (lineNumber++));
...
lineNumber used here
...

You might be wondering: what´s wrong with it? Well, it turns out that this sort of construction it could become extremely difficult to spot in certain conditions. Imagine a hypothetical situation where this code is not working properly in the production environment, and meanwhile the developer in charge of this block of code -the guy as cool as a cucumber- is totally sure about the correctness of it. Okay, you got it, you may be thinking of me: “How noob this guy is!”; but Hey!, sometimes you are toiling late in the night and this kind of bugs pass unnoticed until you receive an email from your Development Manager muttering:

Subject: Potential bug

I have come across with this statement -incidentally- while surfing the code. Beware that the log will be printed out only if the log level is set to DEBUG, so the lineNumber variable won´t be incremented.

All the best,

Your Development Manager

Guess which level the Production Support had established in their environment? Fortunately, I started off saying “Imagine a hypothetical situation …“.

AbstractTransactionalSpringContextTests meets TestNG

Introduction

In the search of an alternative to JUnit, in relation to the testing of our classes, we -Mikel and I- decided to give TestNG a try. This testing framework takes advantage of a useful feature introduced in the release 5.0 of the Java Language: the annotations. In addition, it provides a rich set of facilities to ease the unit and integration testing of Java classes, like groups and data providers. Unfortunately, these are very well explained in the home page of the project, so let´s consider them as being out of the scope in regards to the main thread of this post.

The Problem

What we want to have: test cases running within a transactional context AND take advantage of the TestNG facilities. The former is neatly addressed by a class named AbstractTransactionalSpringContextTests, present in the Spring´s mock package. The latter, well, pretty obvious. What it isn´t so obvious is the way to combine both. Why? TestNG does not provide a direct way to surround the test cases with a transaction, so a rollback action is performed at the end of every test. This way, we are able to avoid side effects between test executions, because one test inserts a row and the next one didn´t expect it, or because a database row is updated between executions breaking some assertions, or because … you get the idea. When we decided to start using TestNG as our main framework for testing, this absence lead us to ask Cedric Beust, the TestNG project leader, about some way to accomplish with the transaction stuff. He responded us very kind and rapidly, recommending to implement the rollbacking in an @AfterMethod method.

TransactionRollbackTearDownTestCase

Note: for this class’s name origin, take a look at this site

Probably Cedric is completely right, but we like how AbstractTransactionalSpringContextTests does its business, and of course, the integration with the Spring´s IoC in order to inject the dependencies to the test classes. For that reason, we have come up with an adapter class, which permits us to run TestNG test cases within the transactional context provided by the Spring class. It is kinda adapter because we change the way the class AbstractTransactionalSpringContextTests is used (i.e. inheriting from it), right now we can extend from the new base class and define our test cases as the usual TestNG manner (i.e. through the use of annotations). It is not an adapter as in the software design patterns.

The class is named TransactionalRollbackTearDownTestCase, and following there is a diagram of its relationships:

TransactionalRollbackTeardownTestCase

The code of this class could prove more descriptive than me trying to explain how it does its job:

package com.centuryminds.test;

import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.test.AbstractTransactionalSpringContextTests;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

/**
 * Base test class which permits: 1) Inject dependencies defined in a Spring
 * context. The aforementioned dependencies must be declared as protected
 * members 2) Perform a rollback action after every test. Basically, it
 * acts as an adapter between the TestNG test case structure and the facilities
 * provided by the class {@link AbstractDependencyInjectionSpringContextTests}
 * in the Spring package
 *
 * @see AbstractDependencyInjectionSpringContextTests
 * @see AfterMethod
 * @see BeforeMethod
 */
public abstract class TransactionRollbackTearDownTestCase extends
		AbstractTransactionalSpringContextTests
{

	/**
	 * Test Fixture
	 *
	 * @throws Exception if a error occurred during the fixture execution
	 * @see {@link AbstractDependencyInjectionSpringContextTests#setUp()}
	 * @see {@link AbstractDependencyInjectionSpringContextTests#setPopulateProtectedVariables(boolean)}
	 */
	@BeforeMethod
	protected final void before() throws Exception
	{
		setPopulateProtectedVariables(true);
		super.setUp();
	}

	/**
	 * Test Teardown
	 *
	 * @throws Exception if a error occurred during the teardown execution
	 * @see {@link AbstractDependencyInjectionSpringContextTests#tearDown()}
	 */
	@AfterMethod
	protected final void after() throws Exception
	{
		super.tearDown();
	}
}

As it can be seen, this class is really simple. It defines two final methods, both TestNG-annotated which delegate the test fixture and teardown actions to the underlying parent implementation. Therefore, every time a test case method is going to be executed, before() will inject the dependencies defined in the Spring context and will create and start a new transaction context. The method tearDown() in turn will perform a rollback action just after the test ends.

Extending the Hierarchy

Obviously, the class above is not enough: where are the dependencies to be injected defined? We have to tell AbstractTransactionalSpringContextTests where to look for them. This can be achieved by a subclass of TransactionalRollbackTearDownTestCase, for example:

package com.centuryminds.test;

/**
 * Base test class that specifies the spring contexts containing the dao
 * definitions. The subclasses must provide an implementation of the method
 * {@link #getConfigLocations()}, specifying the files with the spring contexts
 * holding the definitions of the dao and its dependencies
 */
public class BaseDAOTestCase extends TransactionRollbackTearDownTestCase
{
	/**
	 * @see org.springframework.test.AbstractDependencyInjectionSpringContextTests#getConfigLocations()
	 */
	@Override
	protected String[] getConfigLocations()
	{
		return new String[] { "classpath:applicationContext-datasource.xml",
				"classpath:applicationContext-service.xml" };
	}
}

The Actual Test Class

One important benefit of the separation above is that we could define several BaseDAO* classes, each one of them declaring its own context set. Let´s see an example DAO test class extending from BaseDAOTestCase:

package com.centuryminds.test;

import java.util.HashSet;

import org.testng.annotations.Test;

import com.threefish.aquarium.dao.hibernate.GenericHibernateDAO;
import com.threefish.aquarium.model.Role;
import com.threefish.aquarium.model.User;

/**
 * Tests for RoleDAO
 */
public class RoleDAOTest extends BaseDAOTestCase
{
	/** role dao */
	protected GenericHibernateDAO roleDAO;

	/** role */
	private Role role;

	@Test
	public void testCreate() throws Exception
	{
		int amount = roleDAO.findAll().size();

		// let's create a new role to persist
		role = new Role();
		role.setName("testrole");
		role.setDescription("Master of Universe");
		role.setUsers(new HashSet());

		roleDAO.makePersistent(role);

		assertNotNull(role.getId());
		assertEquals(amount + 1, roleDAO.findAll().size());
	}

	@Test
	public void testSuccessfulGet() throws Exception
	{
		role = roleDAO.findById(Long.valueOf(1));

		assertEquals("admin", role.getName());
	}

	@Test
	public void testUpdate() throws Exception
	{
		role = roleDAO.findById(Long.valueOf(1));
		role.setDescription("Super Administrator Role");
		roleDAO.makePersistent(role);

		assertEquals("Super Administrator Role", role.getDescription());
	}
}

The RoleDAO test class makes use of a custom generic DAO framework, but despite that I think it is pretty self-explanatory. We shall try to explain the generic DAO related interfaces and classes in another post when we get a chance, but for now we have enough.

The test methods are executed within a transaction per test method, which is rollbacked at the very end of it. So, the role insert in the first test (testCreate()), would be rollbacked and future tests depending on the initial state (i.e. the state before testCreate() ran) wouldn´t be affected. We accomplished with the goal of executing the test cases in isolation. Thanks Spring! We accomplished with the goal of using some of the features offered by TestNG. Thanks to you as well!

Future

We are aware about the drawbacks of this solution, and we are pretty sure about the fact that there must exist a more sophisticated solution out there, hence we are very willing to listen to your suggestions to improve the general structure of our current one. We’ll stay tuned …

Jetty Embebido

Una característica muy interesante del servidor Jetty es que puede ser embebido en cualquier aplicación JAVA. Esto nos permite hacer diversas cosas: Desde dar una interfaz de configuración Web a una aplicación no Web, hasta cosas más exóticas como realizar testing de un cliente http.

Lo mejor que tiene es que es facilísimo poner un servlet a escuchar en una url, vamos, cosa de niños. Bueno, no me enrollo más, aquí va el código:

import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
...
server= new Server(8080);
Context root = new Context(server,"/contexto",Context.SESSIONS);
root.addServlet(new ServletHolder(new Servlet(){
 public void destroy() {}
 public ServletConfig getServletConfig() {return null;}
 public String getServletInfo() {return null;}
 public void init(ServletConfig arg0) throws ServletException {}
 public void service(ServletRequest request, ServletResponse response)
         throws ServletException, IOException {
     response.getOutputStream().write"HOLA MUNDO"getBytes());
 }
}), "/servlet");
server.start();
 ...

Y ya tenemos nuestro servlet escuchando en http://localhost:8080/contexto/servlet. Este servlet tampoco hace mucho, pero da una idea de lo fácil que puede ser poner a escuchar un servlet en un Jetty embebido.

Exceptions y JDK 1.3

Yo soy el primero al que le encantaría el poder utilizar las características de la versión 1.5 de Java, en concreto encuentro muy útiles los static imports y los generics, y por supuesto las annotations. Sin embargo, durante mi carrera, y por diversas razones, me he encontrado en situaciones de no poder utilizar siquiera la versión 1.4 del JDK. Es triste, pero cierto, y me temo que es muy habitual encontrarse con la restricción tan temida de: “Tenemos que programar contra el JDK 1.3“. Es algo así como una especie de maldición, cuando estás habituado a utilizar los métodos de la clase String añadidos a partir de la versión 1.4 -replaceAll(), split(), etc-, o la facilidad de la exception chaining. Por fortuna, el proyecto Commons de la fundación Apache puede ayudarnos a solventar algunos de esos obstáculos. Vayamos con la exception chaining. Esta es la interfaz de la clase java.lang.RuntimeException* en la versión 1.4:

public RuntimeException()
public RuntimeException(String message)
public RuntimeException(String message, Throwable cause)
public RuntimeException(Throwable cause)

Como se puede observar, dos de los constructores de esta clase admiten un argumento java.lang.Throwable, por tanto cuando usemos esta clase en la versión 1.4 no perderemos la traza de llamadas de las excepciones. Ahora veamos las signaturas de los constructores de esta misma clase en la versión 1.3:

public RuntimeException()
public RuntimeException(String message)

Ahora ya sabemos que la exception chaining fue un añadido a la versión 1.4 del JDK a la clase RuntimeException. En el subproyecto Commons Lang existe una jerarquía de clases que nos ayudan a establecer una pila de llamadas previa en el constructor de una excepción. En concreto, son las clases NestableRuntimeException y NestableException del paquete org.apache.commons.lang.exception:

Jakarta Commons Exception Hierarchy

Estos son los constructores de la clase NestableRuntimeException:

public NestableRuntimeException()
public NestableRuntimeException(String message)
public NestableRuntimeException(String message, Throwable cause)
public NestableRuntimeException(Throwable cause)

Equivalentes a los de la clase RuntimeException, de forma que funciona como tal y además mantiene una referencia a un objeto Throwable, con lo que simulamos la funcionalidad añadida a la versión 1.4 pero en un entorno compilado para la 1.3. Ahora simplemente podremos definir nuestras propias subclases de NestableRuntimeException o NestableException, sin miedo a que obtengamos errores de compilación debido al overriding de los constructores no existentes en la 1.3, pero sí en la 1.4. Ahora que lo digo, yo he sufrido dichos errores debido a que en mi IDE (Eclipse normalmente) no configuro el proyecto para compilar las fuentes contra la 1.3 (cuando ha de desplegarse en un entorno de JDK 1.3, claro). Aunque ya voy aprendiendo. Considero siempre una buena práctica configurar el entorno de desarrollo a semejanza del entorno destino, en la medida de lo posible.

* También se aplica a la clase java.lang.Exception

Rompiendo Dependencias

5 Freestyler (Boomfunk MC)

Introducción

En un mundo ideal, todos comenzaríamos los proyectos desde cero, podríamos elegir las tecnologías que consideráramos más apropiadas para cada caso, los jefes nos entenderían, nosotros entenderíamos a los jefes, etc. En fin, un Mundo Feliz como el de Aldous Huxley. Sin embargo, para todo el que lleva algo de tiempo en el mundo del desarrollo de software (más o menos con su primer día de trabajo después acabar los estudios ya es suficiente) sabe lo que le toca: mantener código. Según lo veo yo, a esta actividad normalmente se la considera de segundo orden, y no lo es. La confusión es que muchos creen que mantener código pasa casi exclusivamente por cambiar cosas ya hechas o arreglar errores en el código, ya sea tuyo o de otros. Vamos, un sufrimiento. Pero mantener código es mucho más que eso, ya que la propia expresión cambiar cosas ya hechas es demasiado general. Puede abarcar desde cambios en la interfaz de usuario, añadir funcionalidad nueva a la ya existente, eliminar funcionalidad no requerida, mejora del rendimiento, separación y creación de componentes a partir del código actual para ser reutilizado, cambios en el sistema de construcción o despliegue de la aplicación, etcétera etcétera
Como se puede observar, las habilidades requeridas pueden ser muy heterogéneas y abarcar varios campos, e incluso podría decir que es hasta fascinante. Porque al fin y al cabo, la gran mayoría de las aplicaciones evolucionan una vez implantadas hasta que ya no son necesarias, y alguien tiene que hacerse cargo de esa evolución.

Mantenimiento en la Práctica

Muchas veces nos encontramos con código más o menos antiguo, al cual tenemos que añadir funcionalidad nueva o modificar la existente. El problema es que este código es totalmente nuevo para nosotros y no queremos romper nada. Normalmente esto sucede debido a un fuerte acoplamiento entre los componentes del sistema, en un sentido más o menos general: clases, métodos, etc. Un cambio simple en la implementación de un método de una clase puede afectar, transitivamente, a una clase de la que ni siquiera tenemos constancia de su existencia. Puede que el comportamiento erróneo introducido lo descubramos cuando la aplicación está en ejecución, en entornos de QA o Producción. Dependiendo de la tolerancia del proyecto al ciclo de feedback, podemos encontrarnos con una situación inaceptable. Y he aquí la cuestión principal a tener en cuenta: ¿cómo podemos saber si hemos introducido efectos colaterales no deseados en otras partes del sistema? Evidentemente, un sistema software actual puede llegar a ser muy complejo, pero existen formas de mitigar los efectos no deseados de nuestras modificaciones al código. En concreto, estoy hablando de los tests, tanto unitarios como de integración en este caso. Si tenemos un conjunto de tests que prueban la corrección del código existente, podremos sentirnos más seguros a la hora de añadir o modificar funcionalidad. Es por eso que la recomendación en este caso es la de crear ANTES tests para el código sobre el que debemos trabajar. Nos lo agradeceremos nosotros mismos, y nos lo agradecerá el resto del equipo.

Dependencias

Después de haber intentado dejar claro que un buen juego de tests son una especie de seguro de vida, vayamos a su vez con uno de los problemas que nos encontramos cuando queremos crear un test unitario para una clase de este sistema: las dependencias. Algo tan simple como este código puede ser un obstáculo tremendo para acometer lo que nos proponemos:

class A
{
  private B b = new B();

  public void doWhatever()
  {
    b.doBTask();
  }
  ...
}

La clase A tiene una relación de dependencia con la clase B, lo que significa que en el método doWhatever() de A se utiliza la funcionalidad de B. Si la dependencia fuera de uso estaríamos en un caso parecido. Ahora, si queremos crear un test unitario para dicho método de A, estaremos indirectamente invocando al método doBTask() de B. En dos palabras, ya no sería un test unitario. Por tanto, centremos nuestro objetivo en el título de este post: romper dependencias. Aunque primero presentemos un ejemplo un poco más real, que a veces eso de tener clases A y B, más que ayudar, complica la explicación.

De camiones, ruedas y motores

Imaginemos un sistema de información de una empresa de transportes. Cada cierto período de tiempo, esta empresa realiza exhaustivos controles mecánicos a su flota de camiones. Esta podría ser la parte del sistema que nos interesa (obviamente muy simplista):

Trucks, Wheels ...

La clase Truck podría tomar la siguiente forma en el código:

class Truck
{
  private Wheel[] wheels;

  private Engine engine;  public Truck()
  {
    wheels = new Wheel[4]{new Wheel(), new Wheel(), new Wheel(), new Wheel()};
    engine = new Engine();
  }

  public boolean review()
  {
     boolean firstWheelOK = wheels[0].check();
     boolean secondWheelOK = wheels[1].check();
     boolean thirdWheelOK = wheels[2].check();
     boolean fourthWheelOK = wheels[3].check();
     boolean engineOK = engine.check();

     return (engineOK && firstWheelOK && secondWheelOK && thirdEngineOK && fourthEngineOK);
  }
}

La clase anterior, evidentemente, es mejorable en muchos aspectos: ¿4 ruedas fijas?, ¿clase inmutable?, etc. Pero a efectos de ilustrar la rotura parcial de dependencias, nos sirve. Vayamos con el test. Esta técnica es independiente del framework de testing que utilicemos (JUnit en este ejemplo).

class TruckTest extends Test
{
  private Truck truck;

  public void setUp() throws Exception
  {
    truck = new Truck();
  }

  public void testCheck() throws Exception
  {
    assertTrue(truck.review());
  }
}

La llamada truck.review(), implica que se llaman los métodos check() de las ruedas y del motor del camión. Esto sería correcto para un test de integración, pero no para uno unitario. ¿Qué podemos hacer? Pues bien, para todos aquellos afortunados que en su empresa utilizan un framework de IoC, podéis dar por finalizada la lectura de esto aquí. Delegar en Spring por ejemplo la creación y asignación de los objetos miembros de la clase Truck (wheels y engine) es ciertamente algo deseable. Sin embargo, si una aplicación no hace uso de la inversión del control, ya sea por antigüedad o por la razón que sea, mi predicción es que en muchos casos migrar el código para delegar el ciclo de vida de las dependencias a un framework externo como Spring puede ser complicado y producir más de un dolor de cabeza. Así que valgámonos de una propiedad de la OO como es el polimorfismo para crear un test unitario para la clase Truck.

El primer paso va a ser refactorizar la clase para que obtenga las referencias de sus miembros a través de un método accesor (getWheels() y getEngine()):

class Truck
{
  private Wheel[] wheels;

  private Engine engine;  public Truck()
  {
    wheels = getWheels();
    engine = getEngine();
  }

  public boolean review()
  {
    boolean firstWheelOK = wheels[0].check();
    boolean secondWheelOK = wheels[1].check();
    boolean thirdWheelOK = wheels[2].check();
    boolean fourthWheelOK = wheels[3].check();
    boolean engineOK = engine.check();

    return (engineOK && firstWheelOK && secondWheelOK && thirdEngineOK && fourthEngineOK);
  }

  protected Wheel[] getWheels()
  {
    return new Wheel[4]{new Wheel(), new Wheel(), new Wheel(), new Wheel()};
  }

  protected Engine getEngine()
  {
    return new Engine();
  }
}

El segundo paso va a ser crear clases mock de dichas dependencias, de forma que estáticamente podemos definir el comportamiento de éstas y poder así probar la clase Truck en base a este comportamiento definido:

class TruckTest extends Test
{
  private Truck truck;  public void setUp() throws Exception
  {
    truck = new MockTruck();
  }

  public void testCheck() throws Exception
  {
    assertTrue(truck.review());
  }

  protected class MockTruck extends Truck
  {
    protected Wheel[] getWheels()
    {
      /* 1 */
      create and return my own wheels!!!
    }

    protected Engine getEngine()
    {
      /* 2 */
      create and return my own engine!!!
    }
  }
}

Como se puede ver, la clase interna MockTruck es idéntica en comportamiento y estructura a la clase Truck, excepto que sobreescribe los métodos accesores de las dependencias creando y devolviendo las ruedas y el motor cuyos estados definimos nosotros (/* 1 */ y /* 2 */). Con esto hemos conseguido aislar parcialmente la creación dichas dependencias, por lo tanto los tests sobre la clase Truck que definamos suponen un estado y comportamiendo fijo de dichas dependencias. Hemos aislado parcialmente a Truck y ahora sí que TruckTest puede considerarse un test unitario.

Conclusiones

Un problema de uilizar esta técnica de cara al futuro puede ser que queramos crear tests de Truck para diferentes estados de sus dependencias. Tendríamos que crear una clase MockTruck por cada juego de comportamientos, o externalizar la creación de dichas dependencias en los accesores de la clase interna MockTruck, o podríamos … En fin, varias posibilidades. Por supuesto, existen frameworks muy útiles para crear mocks dinámicamente, como jMock o rMock, pero puede ser también complicada su introducción en un sistema no concebido inicialmente para su testing unitario. Por ejemplo, si no se ha seguido la máxima programar contra interfaces, esto es, que no existan o que se programe a través de ellas. Pero vamos, que se decida lo que se decida son respecto al código legado, es preferible tener al menos algo como lo de arriba, a no tener anda.

Algo como Mantenimiento Dirigido por Test, puestos a aportar algo a todo ese océano de siglas con que nos abruman cada día a los programadores.

Registros y Strategy Pattern

5 The kids aren´t alright (Offspring)

Introducción

No sé si será un problema común al que un programador se enfrente a lo largo de su vida, pero durante mi carrera ya me he topado con él un par de veces y, a raíz de un artículo refiriéndose al tema en cuestión, he decidido escribir un algo acerca de ello. Hablo del parseo de registros (record parsing). En concreto, del parseo de registros en archivos de textos, los cuales pueden contener varios tipos de de estos registros sin un orden prefijado y uno por línea.

Registros, registros

Por ejemplo, imaginemos que necesitamos recopilar información acerca de personas físicas. Para ello tenemos dos tipos de registros, uno que contiene el nombre y apellido de la persona, y otro que contiene el nombre, apellido, dirección y ciudad de residencia. Una de las formas más comunes de abordar el problema de cómo diferenciar los distintos tipos de registros es utilizar una cabecera en cada uno, indicando de qué tipo es. Veamos un ejemplo de posible entrada:

01234567890123456789012345678901234567890123456789...
————————————————–…
ONEMichael Smith
TWOTeddy Richardson New York Fifth Avenue

Como se puede apreciar, se utilizan los 3 primeros caracteres de la línea para definir el tipo de registro. En este caso tenemos el tipo ONE, y el tipo TWO. A parte de eso, los diferentes tipos de registros no tienen más campos en común. El objetivo final es obtener el conjunto de registros que recibimos en el fichero, de forma que luego podamos hacer con ellos lo que necesitemos. Muchas veces, proyectos de integración con sistemas antiguos -mainframes especialmente- se abordan compartiendo la información entre éstos y los sistemas nuevos mediante este tipo de ficheros basados en un registro por línea.

Una vez que ya tenemos algo parecido a una especificación informal de la definición del problema y qué necesitamos hacer para resolverlo, vayamos con el cómo. La primera forma que se te ocurre de resolver esto es de sentido común: un bucle que recorre el archivo de texto línea por línea, comprueba qué tipo de cabecera es (un if por cada tipo nos servirá), y obtiene los campos en base a ese tipo. Visto gráficamente:

Parsing flow

La siguiente será la representación de nuestro modelo, del cual queremos crear objetos a partir de los valores presentes en los registros del archivo de texto. Consta de una clase abstracta y dos concretas que extienden de la primera. Se han llamado RecordXXXXX, pero podrían haberse llamado Person o PersonAddress. Hay que recordar que de líneas de texto lo que obtenemos finalmente son objetos reales cuyas propiedades corresponden a los valores parseados en forma de registros. Un aspecto interesante aquí es que las clases no contienen un miembro type que defina qué tipo de registro es. Esto entra en el dominio del parseo y es por tanto responsabilidad de la clase parseadora. Simplemente, ¡no estaría bien aquí!

Basic Model

Y el código asociado:

public abstract class Record
{
}

public class RecordTypeONE extends Record
{
  public String firstName;
  public String lastName;
}

/* I am not a RecordTypeONE, hence do not attempt to make me inherit from it */
public class RecordTypeTWO extends Record {
  public String firstName;
  public String lastName;
  public String city;
  public String address;
}

Nota: para el que se haya alarmado, los campos de las clases los he mantenido public, sin encapsular, con fines de no añadir más complejidad al ejemplo (echa un vistazo al método setValue() de la clase FieldExtractor más abajo, y sabrás por qué).

Y, finalmente, éste es el método que sirve para parsear el conjunto de posibles registros que recibimos en el fichero de texto.

// dentro de una clase...
public List process()
{
  List records = new ArrayList<Record>();
  while (!EOF())
  {
    String line = getNextLine();
    Record record = null;
    if (line.substring(0, 3).equals("ONE")
    {
      record = new RecordTypeONE();
      record.firstName = line.substring(3, 11);
      record.lastName = line.substring(11, 29);
    }
    if (line.substring(0, 3).equals("TWO")
    {
      record = new RecordTypeTWO();
      record.firstName = line.substring(3, 9);
      record.lastName = line.substring(9, 30);
      record.city = line.substring(30, 39);
      record.address = line.substring(39, 60);
    }
    else
    {
      throw new InvalidRecordException("Record type not recognized");
      // or just remove this else block in order to ignore unknown record types
    }
    records.add(record);
  }
  return records;
}

Como vemos, esta solución es bastante sencilla. En principio, es suficiente, y la mayoría de las veces nos empecinamos -yo el primero- en intentar hacer las cosas más complicadas por nuestra tendencia natural a creer que las soluciones sencillas no son las mejores. Sin embargo, es todo lo contrario, las soluciones sencillas son las más efectivas y las más difíciles de dar con ellas. Esto es así porque la simplicidad da respuesta al mayor problema al que se enfrentan la computación en la actualidad: la gestión de la complejidad. Pero esa es otra historia.

Con lo que hoy nos toca, tengo que decir que, aunque sí que es cierto que esta solución al problema es correcta y hasta deseable, puede y debe mejorarse. Esto es así porque por naturaleza, el parseo de registros es cambiante. Estad seguros de que la probabilidad de que se produzca uno de los dos cambios siguientes en los requisitos es muy elevada:

  1. Gestión de los tipos de registros (nuevos, eliminaciones)
  2. Cambio en la composición de un registro (nuevos campos, eliminaciones, cambios de lugar)

Este es uno de esos casos en los que defenderse ante estos cambios es más económico que gestionarlos dentro del propio método, bien añadiendo o quitando bloques condicionales, modificando el contenido de éstos para hacer frente al punto 2 expuesto anteriormente, etc. Una de las herramientas más potentes con las que cuenta un programador utilizando un lenguaje orientado a objetos son los Patrones de Diseño. En pocas palabras,son soluciones documentadas a problemas de diseño conocidos que han funcionado en el pasado y siguen haciéndolo en la actualidad. Veamos un ejemplo de uno de los más sencillos y útiles, aplicándolo a nuestro problema de los cambios potenciales en el parseo de registros.

Introducción al Strategy Pattern

Este patrón es de los primeros que se explican en la mayoría de cursos. Básicamente se utiliza para aislar el comportamiento de un objeto del propio objeto. Se ve bastante claro en la siguiente figura:

Strategy Hierarchy

El comportamiento del que hablábamos, esto es, la funcionalidad que provee el método perform(), se ha externalizado a una nueva jerarquía simple de clases, de forma que Context simplemente llama a este método, sin saber cómo se ejecuta. Y aquí está la clave, como Context no sabe qué implementación se ejecuta (de hecho, le da igual), se puede cambiar la implementación en cualquier momento, incluso en tiempo de ejecución, entre las diferentes estrategias (Strategy1, etc).

Ventajas de hacerlo así, son varias:

  1. Como hemos dicho, se puede cambiar la implementación en cualquier momento
  2. Está más estructurado el conjunto de implementaciones, ya que cada una está en una clase. Esto
    falicita el mantenimiento. Se pueden añadir nuevas implementaciones y quitar o modificar las existentes de una forma muy limpia y eficiente
  3. Es útil para reducir el número de clases en el sistema. Si varias clases son prácticamente la misma
    pero difieren en el comportamiento, a lo que ayuda este patrón es a tener una única clase que utiliza
    las diferentes estrategias (comportamientos)
  4. Por supuesto, como veremos más adelante, nos ahorramos ese conjunto de bloques condicionales que
    siempre ensombrecen la elegancia de nuestro código

El Strategy Pattern en acción

Veamos ahora como encaja este patrón en nuestro ejemplo. La clase FieldExtractor enlaza una ristra de caracteres (con índices superior e inferior) con la propiedad correspondiente en un objeto Record. Un método interesante de esta clase es setValue(), ya que utiliza la Reflection API para establecer el valor de la propiedad del objeto Record, que como se verá después, el objeto FieldExtractor sólo conoce en tiempo de ejecución.

public class FieldExtractor
{
  protected int start;
  protected int end;
  protected String propertyName;
  public FieldExtractor(int start, int end, String propertyName)
  {
    this.start = start;
    this.end = end;
    this.propertyName = propertyName;
  }
  public void extractField(String line, Record record)
  {
    String value = line.substring(start, end + 1);
    setValue(record, value);
  }
  // Reflection API to the rescue!
  protected void setValue(Record record, String value)
  {
    Field field = record.getClass().getField(propertyName);
    field.set(record, value);
  }
}

La intefaz RecordReader define los métodos destinados al parseo de registros a partir de líneas de texto, usando objetos FieldExtractor para dicha función.

public interface RecordReader
{
  String getType();
  void addFieldExtractor(FieldExtractor fieldExtractor);
  Record processLine(String line);
}

La siguiente implementación básica da una idea más específica del funcionamiento del parseo de un registro, dada una línea de texto. Como se puede apreciar, mantiene referencias a un conjunto de objetos FieldExtractor, y cuando el método processLine() es invocado, los recorre todos, de forma que al final se obtiene un objeto Record con todos sus campos rellenos a partir de la línea de texto. También contiene referencias a la cadena de texto que define el tipo de registro que se encarga de parsear, así como su clase.

public class RecordReaderImpl implements RecordReader
{
  protected String type;
  protected Class recordClass;
  protected List fieldExtractors = new ArrayList();
  public RecordReaderImpl(String type, Class recordClass)
  {
    this.type = type;
    this.recordClass = recordClass;
  }
  public String getType()
  {
    return type;
  }
  public void addFieldExtractor(FieldExtractor fieldExtractor)
  {
    fieldExtractors.add(fieldExtractor);
  }
  public Record processLine(String line)
  {
    Record record = recordClass.newInstance();
    for (FieldExtractor extractor : fieldExtractors)
    {
      extractor.extractField(line, record);
    }
    return record;
  }
}

La ventaja de todo esto es que, para cada tipo de registro, no vamos a tener que definirnos una clase de forma separada, o cómo hacíamos antes, definir un nuevo bloque condicional asociado a su parseo. En cierto sentido, hemos cambiado creación por configuración. Es decir, en vez de crear un montón de clases parseadoras específicas a cada tipo de registro, simplemente tenemos una única clase, lo bastante flexible como para poder crear a partir de ellas objetos parseadores de forma dinánima. Y la de código -y mantenimiento- que nos hemos ahorrado.

Todo lo anterior no es muy útil sin un cliente que haga uso de ello. Para ello nos definimos una clase RecordProcessor, que será la encargada de recorrer línea por línea el archivo de texto y obtener finalmente el conjunto de objetos Record.

public class RecordProcessor
{
  RecordReaderConfiguration config;
  public RecordProcessor()
  {
    config.setUp();
  }
  public List process()
  {
    List records = new ArrayList();
    while (!EOF())
    {
      String line = getNextLine();
      RecordReader reader = config.getRecordReader(line);
      Record record = reader.processLine(line);
      records.add(record);
    }
    return records;
  }
}

Como vemos, RecordProcessor es bastante sencilla, invocando para cada línea a un objeto RecordReader, visto anteriormente. Lo interesante aquí es cómo se obtienen estos objetos RecordReader en tiempo de ejecución. Para ello, la clase RecordProcessor mantiene una referencia a un objeto RecordReaderConfiguration.

public class RecordReaderConfiguration
{
  protected Map recordReaders;
  public void setUp()
  {
    addRecordType1();
    addRecordType2();
  }
  public RecordReader getRecordReader(String line)
  {
    String type = line.substring(0, 3);
    RecordReader recordReader = recordReaders.get(type);
    if (recordReader == null) throw new IllegalArgumentException("Type does not exist");
    return recordReader;
  }
  protected addRecordType1()
  {
    RecordReader recordReader = new RecordReaderImpl("ONE", RecordTypeONE.class);
    recordReader.addFieldExtractor(new FieldExtractor(3, 11, "firstName"));
    recordReader.addFieldExtractor(new FieldExtractor(12, 28, "lastName"));
    recordReaders.add(recordReader.getType(), recordReader);
  }
  protected addRecordType2()
  {
    RecordReader recordReader = new RecordReaderImpl("TWO", RecordTypeTWO.class);
    recordReader.addFieldExtractor(new FieldExtractor(3, 11, "firstName"));
    recordReader.addFieldExtractor(new FieldExtractor(12, 28, "lastName"));
    recordReader.addFieldExtractor(new FieldExtractor(29, 40, "city"));
    recordReader.addFieldExtractor(new FieldExtractor(41, 59, "address"));
    recordReaders.add(recordReader.getType(), recordReader);
  }
}

Aquí es donde se hace el trabajo duro de parseo. El método setUp() -llamado por RecordProcessor en su constructor- se encarga de añadir los objetos RecordReader que parsearán el conjunto de todos los registros que pueden encontrarse en el fichero de texto. Estos objetos son almacenados en un Map, de forma que las keys del Map las forman los strings representando los distintos tipos de registro, y los values los forman a su vez los objetos RecordReader.

Finalmente, este es el aspecto que tiene el conjunto de clases e interfaces que he definido más arriba:

Final Structure

Gestión de cambios

Veamos cómo afectarían los cambios a esta nueva disposición de clases basadas en el Strategy Pattern.

1. Gestión de los tipos de registros (nuevos, eliminaciones)

Añadir un nuevo tipo, es tan sencillo como registrar un nuevo tipo de RecordReader en la clase RecordReaderConfiguration

2. Cambio en la composición de un registro (nuevos campos, eliminaciones, cambios de lugar)

Basta con modificar el cuerpo de los métodos en los que se crean los RecordReaders de la clase RecordReaderConfiguration -addRecordTypeXX()-

Notas finales
Supongo que todos aquellos fans -con razón- de los frameworks IoC (Spring, PicoContainer, MicroContrainer,etc), se habrán percatado de la gran ventaja de tener la configuración de los RecordReaders dentro de una clase separada (RecordReaderConfiguration). Os dejo para vosotros un asunto pendiente tan interesante como externalizar dicha configuración a una fuente externa (XML?) e inyectarla a la clase RecordProcessor.

Bibliografía