Need help in the bundle jungle...

It's easy as pie getting lost in the bundle jungle!

A few weeks ago I introduced in DRY iBatis DAOs build an UserDetailsService an iBatis based UserService. To reduce the required number of seven bundles and additional infrastructural requirements like a database we want to use a simple stupid stub implementation.

In the first step, we extract bundle No. eight userservice.api and implement bundle No. nine the userservice.stub. Ups we did it again - even more bundles in the jungle. Out of the now nine bundles we choose the following four to escape the bundle jungle during the time of development.

  • userservice.model - yeah right, a User;-)
  • userservice.api - the new bundle in the jungle, the UserService API
  • userservice.stub - a HashMap based UserService stub implementation
  • userservice.security - a thin adapter implementation publishing the service as UserDetailsService inside the OSGi container

We removed all database/iBatis dependencies from the development workspace. With the userservice.api-bundle we opened the door for other implementations: e.g. LDAP, ADS, ...

The API could look like this:

public interface UserService {

/**
  * Register a new {@link User}.
  * @param newUser the new user's data.
  */
void registerUser(User newUser);

/**
  * Load registered {@link User} by a given id.
  * @param username of the {@link User} to load.
  * @return the {@link User} identified by the given id.
  */
User loadUserByUsername(String username);
...

Let's write some Groovy test cases.

public class UserServiceStubGroovyTests {

UserService userService = new UserServiceStub()

  @Test
  public void testGetEmptyList() {
    assertTrue(userService.getList().isEmpty())
  }

  @Test
  public void testLoadUserByUsername() {
    userService.registerUser(new UserImpl("J.Unit", "junit@invalid.com"))
    assertNotNull(userService.loadUserByUsername("J.Unit"))
  }

  @Test
  public void testRemoval() {
    userService.registerUser(new UserImpl("J.Unit", "junit@invalid.com"))
    userService.remove(42)
    assertTrue(userService.getList().isEmpty())
  }
}

Now go for the green bar! With a HashMap based stub implementation:

public class UserServiceStub implements UserService {

  private static final AtomicInteger COUNTER = new AtomicInteger(41);
  private final Map<Integer, User> users = new ConcurrentHashMap<Integer, User>();

  @Override
  public void registerUser(User newUser) {
    users.put(COUNTER.getAndIncrement(), newUser);
  }

  @Override
  public User loadUserByUsername(String username) {
  for (User user : users.values()) {
    if (user.getUsername().equals(username)) {
      return user;
    }
  }
  throw new IllegalArgumentException();
}

@Override
public void remove(Integer id) {
  users.remove(id);
}
...

Wasn't it easy as pie to escape the bundle jungle?


Photo by Filippo Cesarini from Burst