Basic Spring MVC spring-servlet.xml Configuration

Tonight, I enjoyed a nice success. Specifically, I enjoyed the kind of success that I’ve found tends invariably to arise from using TDD — I wired some things together and discovered that everything just worked (well, at least my java code did – I did have a slight oops with javascript typos, but that’s to be expected in an environment where I get no feedback until runtime). And, what made this extra sweet is that I’m designing a server that turns lights on and off in my house. This means that at the eureka, breakthrough moment, you don’t find out from a running application or a successfully parsed file or anything as mundane as that. You’re treated to your house lighting up like a Christmas Tree to celebrate your success! (And then you’re thankful that the “off” also works because your sleeping girlfriend is probably not amused by this development.)

But, my purpose here is neither to gloat nor to stump for TDD. Instead, I wanted to give a nod to how easy it was for me to wire things up in Spring MVC 3, and what an improvement I perceive this to be from some years and versions back. Since I was doing TDD, I was basically isolating two classes that I have collaborating them and testing them individually. These classes are LightManipulationServiceHeyuImpl, which implements LightManipulationService and LightController:

public interface LightManipulationService {

	/**
	 * Turns the light in question on or off
	 * @param light - the light to toggle
	 * @param isOn - the setting (true for on, false for off)
	 * @return whether or not the operation was successful
	 */
	Boolean toggleLight(Light light, Boolean isOn);
	
	/**
	 * Change the brightness of a light
	 * @param light - the light to modify
	 * @param brightnessChange - the brightness change (positive for brighter, negative for dimmer)
	 * @return whether or not the operation succeeded
	 */
	Boolean changeBrightness(Light light, int brightnessChange);
}

public class LightManipulationServiceHeyuImpl implements LightManipulationService {

	public static final String OFF_COMMAND = "off ";

	public static final String ON_COMMAND = "on ";

	public static final String HEYU_COMMAND = "/usr/local/heyu-2.6.0/heyu ";
	
	private Runtime _runtime;
	
	/**
	 * Dependency injected constructor
	 * @param runtime - runtime to use for executing shell commands
	 */
	public LightManipulationServiceHeyuImpl(Runtime runtime) {
		if(runtime == null)
			throw new IllegalArgumentException("runtime");
		_runtime = runtime;
	}
	
	@Override
	public Boolean toggleLight(Light light, Boolean isOn) {
		try {
			String myCommand = isOn ? ON_COMMAND : OFF_COMMAND;
			return _runtime.exec(HEYU_COMMAND + myCommand + light.getLightCode()) != null;
		} catch (IOException e) {
			return false;
		}
	}

	@Override
	public Boolean changeBrightness(Light light, int brightnessChange) {
		// TODO Auto-generated method stub
		return null;
	}
}

RequestMapping("/light")
public class LightController {

	private LightManipulationService _lightService;
	
	public LightController(LightManipulationService lightManipulationService) {
		if(lightManipulationService == null) throw new IllegalArgumentException("lightManipulationService");
		_lightService = lightManipulationService;
	}

	@RequestMapping("/light")
	public ModelAndView light() {
		return new ModelAndView();
	}

	/**
	 * Toggles the light described by room and light names on or off (command)
	 * @param room - Name of the room we find this light in
	 * @param light - Name of the light itself
	 * @param command - Whether to turn the light on or off
	 */
	@RequestMapping(value="/{room}/{light}/{command}", method=RequestMethod.PUT)
	public void toggleLight(@PathVariable String room, @PathVariable String light, @PathVariable String command) {
		_lightService.toggleLight(new Light(room, light), command.toLowerCase().equals("on"));
	}
}

This was all tested and looking good for the time being, so I figured I’d take a break from implementation and, well, see if any of it actually worked. Up until this point, I hadn’t bothered with any wireup, so I figured this would be an adventure. But, it wasn’t. A little google-fu and everything worked. I figured it would be easy enough to declare beans to do setter injection (I remembered this from the Spring MVC 1 days), but I thought that I might get snagged a little with constructor injection. I thought I might get snagged a lot with the fact that I wanted to inject the result of the static method Runtime.getRuntime() into my service.

But, I had no trouble in either case.

    <bean id="shell" class="java.lang.Runtime" factory-method="getRuntime"/>
    
    <bean id="heyuService" class="com.daedtech.daedalus.services.LightManipulationServiceHeyuImpl">
    	<constructor-arg index="0" type="java.lang.Runtime" ref="shell"/>
    </bean>
    
    
    <bean id="lightController" class="com.daedtech.daedalus.controller.LightController">
    	<constructor-arg index="0" ref="heyuService"/>
    </bean>

The first thing I set up was my service, using the familiar bean id and class syntax. From here, I located the constructor injection tag, but decided to come back to it since I thought the static method was going to be ugly. I then created the lightController bean and this is when I found the syntax for the constructor injection tag: constructor-arg. I specified which 0-indexed constructor argument I was supplying and referred it to my service bean. Simple enough. I don’t know whether the index is necessary with only one parameter or not, but hey, it’s working. I’ll figure that out when I need to.

From there, the static thing was surprisingly and pleasantly easy. I don’t know whether Runtime.getRuntime() is actually considered a factory method or not, but by using it in this fashion, I was able to accomplish what I wanted. This is going to come in extremely handy for cases where I have to pull things out of some framework or library static state and I don’t want to take that inline dependency to impede flexibility/testability.

And, really, that was it. I fired this up with my unit tested classes and absolutely nothing happened. I peered at the JSP pages and the javascript in them, realized I had forgotten a comma, fired again, and was dazzled by the lightshow in my house. So kudos to Spring MVC. Easy and flexible is always nice.