Saturday, January 31, 2009

When Collections Are Configuration - binding Collections in Guice

Classes that create their own internal domain objects and simple objects are typically not a problem for testability. The problem comes when classes are creating their own dependent services internally. Then, you've got a problem cutting the testing seams. Creating these dependent services is what Dependency Injection is best at. Using your IoC container to create everything constitutes container abuse.

However, I will use my IoC container of preference to create populated collections if the contents of those collections are inherently configuration. For instance, assume we have the following class:


public class Validator<T> {
private Collection<Validation<T>> validations;
private ValidationProblemReporter reporter;

public Validator(Collection<Validation<T>> validations,
ValidationProblemReporter reporter) {
this.validations = validations;
this.reporter = reporter;
}

public validate(Collection<T> elements) {
for(Validation<T> validation : validations) {
for(T elements : elements) {
if (!validation.isValid(element)) {
String m = element.toString() + " fails " + validation.toString();
reporter.reportProblem(m);
}
}
}
}
}


we frequently use a validation pattern that calls for a Collection<Validation<T>>. These validations vary from project to project, but the Validator<T> class is the same from project to project. The actual validations used varies depending on the validation requirements of the project and the type of the object that is being validated. Each instance of Validation<T> is pure business logic, and each is properly unit tested.

Determining what to put in the Collection<Validation<T>> is simply a configuration concern. This is where it is easy to use the IoC container. Since Guice is what I typically use, that's what I'll show.

Example: Say, we are dealing with Customer objects that we are importing into the system. These customers are being imported from someone else's system into ours. So, we are not sure if each customer object is valid and we only want to import the objects that are valid. There are multiple ways to bind up the collection of validations, among them are using TypeLiteral and using a marker class. For this, I will show the marker class, but I've also used TypeLiteral.

So, since I want to validate Customer, I create a class like:


public class CustomerValidations extends ArrayList<Validation<Customer>> {
//marker class
}


Now, I'll write a marker for the validator:


public class CustomerValidator extends Validator<Customer> {
@Inject
public CustomerValidator(CustomerValidations validations,
ValidationProblemReporter reporter) {
super(validations, reporter);
}
}


To get Guice to inject the dependencies into the CustomerValidator, we'll need to bind CustomerValidations and ValidationProblemReporter. So, I would have a Guice Module that looks something like:


public MyModule extends AbstractModule {
public void configure() {
bind(ValidationProblemReporter.class).to(ConsoleReporter.class);
bind(CustomerValidations.clas).to(CustomerValidationsProvider.class);
}
}


We'll have to write the provider for the CustomerValidations:


public class CustomerValidationsProvider implements Provider<CustomerValidations> {
public CustomerValidations get() {
validations = new CustomerValidations();
validations.add(new CustomerShouldHaveAName());
validations.add(new CustomerShouldHaveAnEmailAddress());
...

return validations;
}
}


This cuts a very nice seam to configure which validations we want to run over our customers. I can easily write a unit test that asserts what validations we have configured. In fact, if order is important, then I can check that as well.


public class CustomerValidationsTest {
@Test
public void we_should_do_the_right_things_in_the_right_order() {
CustomerValidationsProvider provider = new CustomerValidationsProvider();
CustomerValidations validations = provider.get();
Iterator<Validation<Customer>> iterator = validations.iterator();

assertEquals(CustomerShouldHaveAName.class, iterator.next().getClass());
assertEquals(CustomerShouldHaveAnEmailAddress.class, iterator.next().getClass());
assertFalse("Should not have any more", iterator.hasNext());
}
}


Now, we have locked down our configuration such that if we change the validations, we have to change this test. I wouldn't always lock the configuration like this, but I often do.

Guice allows you to unit test your configuration (since it's all Java). Figuring out what needs tested and what doesn't can be an art form. You'll get a better feel for it with experience.

Thursday, January 22, 2009

Hudson Default Ant

Most Hudson configuration is self-explanatory and easy to find in the web configuration. Many props go to the developers of Hudson because it is quite easy to setup and use. However, there are a couple of things that I've found lately that don't seem to be documented in the Hudson docs.

Configuring Ant


From the Hudson dashboard, click on
  Manage Hudson -> Configure System
or you can simply navigate to
  http://your-server-here/hudson/configure

Look for the section labeled "Ant" and add your Ant installations by clicking "Add" and providing a name and the absolute path for ANT_HOME. This couldn't be simpler.

Default Ant


When you are configuring a build, you can tell Hudson which Ant you want to use. You may either use one of the named Ant installations that you previously added, or Hudson gives you the option of using the "Default Ant."

For some reason, I was thinking that I had somehow set the only Ant installation that I added as the default (since it was indeed the only one). But, this was not the case, and my build failed with this console output:

FATAL: command execution failed.Maybe you need to configure the job to choose one of your Ant installations?
java.io.IOException: Cannot run program "ant" (in directory "/home/tomcat/hudson/jobs//workspace/build")


Then, I got to looking at how to set the default Ant, and I could not for the life of me find the setting anywhere. This is because, there is NO default that can be changed from within Hudson.

If you tell Hudson to use the default Ant for a build, then it will use whatever ant it finds on the PATH. Note that I did not say that Hudson will use whatever ANT_HOME points to. Hudson must be able to find the ant command on the PATH.

In our case, Hudson runs as the user 'tomcat.'

So, if I wanted to use the default Ant for a build, I would typically solve this by setting both the ANT_HOME and PATH environment variables for the tomcat user. I would set ANT_HOME to the Ant installation that I wish to use as default, and I would then add $ANT_HOME/bin to the PATH environment variable.

What I Actually Did


Since I really didn't care to go to all that trouble of setting environment variables, I just used the named Ant instance that I had already configured in Hudson. We do not have a default Ant available to Hudson, and it's not a problem.

Wednesday, January 21, 2009

Hudson Gets an AccessControlException when starting on Ubuntu Tomcat

With fresh install of Ubuntu 8.10 I grabbed Tomcat 6 from Synaptic. Then, I dropped the hudson.war into the Tomcat webapps directory, and was greeted with an AccessControlException and a Hudson that would not start.

This is because on Ubuntu, Tomcat default installs with the Tomcat Security Manager enabled. This is probably a good thing for many installs of Tomcat, but it interferes with Hudson. When we finally found the problem, we took the lazy road and disabled the Tomcat Security. Depending on your install, this may be an unsafe decision. I would check the Tomcat documentation before doing this if your server is externally exposed. In our environment, the build server is on a completely trusted network. So, we didn't care much.

Here is the stack trace that is displayed when first trying to browse to the Hudson app:


HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: Error instantiating servlet class org.kohsuke.stapler.Stapler
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
java.lang.Thread.run(Thread.java:636)

root cause

java.lang.ExceptionInInitializerError
org.apache.commons.beanutils.ConvertUtilsBean.(ConvertUtilsBean.java:130)
org.kohsuke.stapler.Stapler.(Stapler.java:659)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
java.lang.reflect.Constructor.newInstance(Constructor.java:532)
java.lang.Class.newInstance0(Class.java:372)
java.lang.Class.newInstance(Class.java:325)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
java.lang.Thread.run(Thread.java:636)

root cause

java.security.AccessControlException: access denied (java.util.PropertyPermission org.apache.commons.logging.LogFactory.HashtableImpl read)
java.security.AccessControlContext.checkPermission(AccessControlContext.java:342)
java.security.AccessController.checkPermission(AccessController.java:553)
java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1302)
java.lang.System.getProperty(System.java:669)
org.apache.commons.logging.LogFactory.createFactoryStore(LogFactory.java:320)
org.apache.commons.logging.LogFactory.(LogFactory.java:1725)
org.apache.commons.beanutils.ConvertUtilsBean.(ConvertUtilsBean.java:130)
org.kohsuke.stapler.Stapler.(Stapler.java:659)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
java.lang.reflect.Constructor.newInstance(Constructor.java:532)
java.lang.Class.newInstance0(Class.java:372)
java.lang.Class.newInstance(Class.java:325)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
java.lang.Thread.run(Thread.java:636)

note The full stack trace of the root cause is available in the Apache Tomcat/6.0.18 logs.



This was fixed by changing:

/etc/default/tomcat6


And setting the following property:

# Use the Java security manager? (yes/no, default: yes)
# WARNING: Do not disable the security manager unless you understand
# the consequences!
#TOMCAT6_SECURITY=yes
TOMCAT6_SECURITY=no


Note that we left the commented example in place for future reference. I hope this helps someone else. Mostly, I'm hoping that by writing this down, I will remember this in the future or at least be able to find the solution quicker.

Go forth and write tests...

Wednesday, January 14, 2009

Cool Code Snippet Tool

Simple post for my own memory:

The best online code snippet posting tool that I've found is at http://pastebin.com/. It has great syntax highlighting for a variety of languages (including Groovy) and it is very easy to use.

Wednesday, January 7, 2009

Tests Drive Good Design

Test-first development leads to better design in the production code. Specifically, you get much lower coupling (both internally and externally), and you get much higher cohesion.

For those of you unfamiliar with those two terms, Coupling is tying one class to another. For instance, if ClassA relies on ClassB to do some work in such a way that a break in ClassB causes unit tests for ClassA to break, that's coupling. We try to limit coupling so that individual classes are isolated. We will always be coupling our classes to a degre (if java.lang.String breaks, everything breaks), but we try to keep it to a minimum. We want classes with low coupling because it is easier to isolate change.

Cohesion is how well the responsibilities within a class relate to each other. Highly cohesive classes tend to be small chunks that are easy to understand because they have a single responsibility. If you are tempted to answer the question, "What does this class do?" by using the word "and" a bunch, then you have a class with low cohesion. We want classes with high cohesion because they are easier to understand and thus easier to change.

When you write good unit tests, especially when you write them first, its easy to detect classes that are NOT highly cohesive and have low coupling. Tests become much more difficult to write when you stray from sound coding practices. If you weren't writing unit tests, you might be tempted to simply "new up" a dependency. Testing drives one to inject dependencies to create better seams and better class isolation.

The bottom line is that testable code is better code. It is easier to change, easier to understand, and overall easier to support.