Archive for the 'Lightwire' Category
Lightwire Tutorial 1: The Basics
Friday, March 12th, 2010

Following up on my last post regarding Lightwire Aspect Oriented Programming (AOP), I thought I’d write up some tutorials to help people get familiaried with Lightwire itself, since I didn’t see a ton of info around. The harder part is actually getting comfortable with the concepts of dependency injection and AOP. Once you got those figured out, Lightwire is stupidly easy to use.

In this post, I’ll cover the concept of dependency injection and leave AOP for another post. Dependency injection is basically a way to ensure that your code is more loosely coupled. As it turns out, it can also make it a heck of a lot easier to use your objects. As an example, I’ll use something simple that will hopefully demonstrate the concept well. I’m going to take a simple service bean (a bean is just a CFC) and a logger bean and show different ways to make them work together. The service bean could do anything, its functionality is irrelevant to this example.

<!--- Logger.cfc --->
<cfcomponent>
	<cffunction name="init" returntype="Logger">
		<cfreturn this />
	</cffunction>

	<cffunction name="log" returntype="void">
		<cfargument name="text" type="string" />

		<!--- Here there would be some code to log things somewhere (a file, DB, etc.) --->
		</cffunction>
	</cfcomponent>

The above illustrates highly coupled components. What’s wrong with it? Technically speaking, nothing. It won’t throw errors or anything (unless I screwed up something!) But the two components are tightly coupled. Imagine if you want to change the class you use for logging? In this simple scenario, it’s pretty simple, all you need to do is change that one call, but what if you have 100 service beans and all of them use the Logger bean? It becomes a bit more painful, right? OK, OK, you could do a Find/Replace in your IDE, but you catch my drift. The other problem is that you will need to manually instantiate the logger bean in every component, which is tedious and violates the DRY principle. Finally, you sometimes want a bean to be a singleton, meaning there’s only one instance of it for the entire application. You need something to manage that.

Here’s another way to go about it (the logger component stays the same so I won’t repeat it here, assume it’s the same as the one above):

<!--- Service.cfc --->
<cfcomponent>
	<cffunction name="init" returntype="Engine">
		<cfargument name="logger" type="Logger" required="yes" />

		<cfset variables.logger = arguments.logger />

		<cfreturn this />
	</cffunction>

	<cffunction name="doSomething" returntype="void">
		<cfset variables.logger.log("Hello world!") />

		<!--- Perform more actions here, anything --->
	</cffunction>
</cfcomponent>

<!--- ServiceFactory.cfm --->
<cfcomponent>
	<cffunction name="init" returntype="ServiceFactory">
		<cfreturn this />
	</cffunction>

	<cffunction name="getService" returntype="Service">
		<cfif NOT structKeyExists(variables, "service")>
			<cfset variables.service = createObject("component", "Service").init( createObject("component", "Logger").init() ) />
		</cfif>

		<cfreturn variables.service />
	</cffunction>
</cfcomponent>

Using the above, things are a little better. The Service bean receives the Logger bean when created and doesn’t have to worry about how it gets instantiated. However, you’re still left with the tedious task of creating the factory, instantiating the Logger manually, etc. Imagine if you wanted the logger to behave similarly. You’d have to create a factory for it to. And imagine if the logger object had dependencies of its own. You can see how this can get really ugly. That’s when a dependency framework comes to the rescue. Here’s how you would do things with lightwire:

<!--- BeanConfig --->
<cfcomponent extends="lightwire.BaseConfigObject" hint="A LightWire configuration bean.">

	<cffunction name="init" output="false" returntype="any" hint="I initialize the config bean.">
		<cfset addSingleton("cfcPath.Service", "Service") />
		<cfset addSingleton("cfcPath.Logger") />
		<cfset addConstructorDependency("Service", "Logger") />

		<cfreturn this />
	</cffunction>

</cfcomponent>

<!--- index.cfm --->
<cfset config = createObject("component","cfcPath.BeanConfig").init() />
<cfset lightwire = createObject("component","lightwire.LightWire").init(config) />

<cfset service = lightwire.getBean("Service") />

In the example above, assume that Logger.cfc is the same as the first example and Service.cfc is the same as the second example. With that out of the way, here’s what’s happening in the above. In the configuration bean, you’re giving Lightwire the definition for your beans. The addSingleton() function is used to define a singleton bean, and you could use addTransient() in the same way to define a transient bean. Within that function call, you specify the path of the component in the first argument and the name of the bean as the second. If the name of the bean is the same as the last part of the path, you don’t need to specify it. You then use the addConstructorDependency() to wire the beans together. The first argument is the bean you want to inject something into, the second is the bean to inject. Then the index.cfm file shows how to start Lightwire and get a bean from it. So the getBean() call basically retrieves a bean based on the configuration above. So behind the scene, something is happening to do createObject(“component”, “cfcPath.Service”).init(createObject(“component”, “cfcPath.Logger”).init()); without you having to type all that. Imagine how useful that is when you have tons of beans with lots of dependencies, that are reused in many other beans. Priceless. Note that since we defined the beans as singletons Lightwire will only instantiate them once in its lifetime. So if you store Lightwire in a persistent scope, like the application scope, your beans will only get created once, saving you the overhead of creating them over and over.

There are 3 ways to inject beans in Lightwire. The first is the one described above, using a constructor dependency. In that case, you add an argument to your bean’s init() function matching the name of the bean to be injected (or you can specify a different name as the third argument of the addConstructorDependency() function). A second way is a setter injection. For a setter injection, you would use addSetterDependency() function. The arguments are the same as for the constructor function, but to get the bean injected you need to define a method in the receiving bean named “set[BeanName]“. Finally, there’s mixin injection. You can add a mixin dependency by using the addMixinDependency() function, which works exactly like the other two, the difference is you don’t need to do anything in the receiving bean. The injection will be done behind the scenes and you don’t have to worry about a thing.

How do you know which injection type to use? It really depends. If you have two beans that both depend on each other, you can’t use constructor dependency, otherwise you’ll run into a circular reference problem. So you can use setter or mixin dependencies in those cases. If you need to use the injected bean in the init() method of the receiving bean, you’ll probably want to use constructor injection. Then it’s down to preference. Some people don’t like mixin injection because they feel it hides part of the implementation and can be confusing to an outsider looking at your application. But I find it invaluable, saves me from adding all those constructor arguments or setter methods. When I have a bean I want to inject pretty much everywhere (like a Utility bean, for example), I usually use mixin injection.

You can also inject regular properties using addConstructorProperty(), addSetterProperty(), and addMixinProperty(). All those take 3 arguments, the name of the bean, the name of the property, and the value of the property.

So this ought to cover the basics of DI and how to use Lightwire for that purpose. Stay tuned for a post on Lightwire and AOP (I’ve already done one, but I’m gonna try to make one that’s actually clear!)

Aspect Oriented Programming (AOP) with Lightwire
Friday, March 12th, 2010

I’m a big fan of Peter Bell’s Lightwire framework. I’ve been using it for quite a while for dependency injection and I love it. However, it’s been lacking a key feature that ColdSpring has: Aspect Oriented Programming (AOP). No more. I’ve taken some time to add some AOP magic to Lightwire and although I haven’t been able to test much yet, it’s looking pretty good so far.

First things first, I gotta give much credit to the developers of ColdSpring. My implementation was very much inspired by their work and made it that much easier to get things done. For users of ColdSpring, things will look rather familiar, I’ve implemented Before, After, Around, and Exception advices in Lightwire, all of which are supported by ColdSprings, albeit some with slightly different names.

For users of Lightwire, AOP is implemented with the same simplicity as the rest of the framework and is a breeze to use. Advices are defined in the configuration bean in a similar way as beans. There is a method for each type of advice: addBeforeAdvice(), addAfterAdvice(), addAroundAdvice(), and addExceptionAdvice(). The arguments for these four methods are the same, so I’m just going to show addBeforeAdvice():

addBeforeAdvice(
	beanName,	// The name of a Lightwire bean that you want to give advice to
	adviceBeanName,	// The name of a Lightwire bean that provides advice
	[methods],	// Optional, methods that the advice applies to; defaults to *, which means all, can be a comma delimited list of method names
	[adviceMethod]	// Optional, name of the advice method, which defaults to the advice type (before, after, around, or exception) if not specified
);

Note that neither of the beans specified above need to extend anything. They can be any bean, any class, extending anything else you want. Now, let’s take a look at what parameters the advice bean methods should receive. Note that I’m going to use the default method names, but you can set the advice method to whatever you want using the optional adviceMethod argument.

before(
	method,	// The method that triggered the advice
	args,	// The arguments passed into the method (struct)
	target	// The bean that contains the method that triggered the advice
);

after(
	method,		// The method that triggered the advice
	args,		// The arguments passed into the method (struct)
	target,		// The bean that contains the method that triggered the advice
	[returnVal]	// Will return a value if the triggering function returned something
);

around(
	AdviceDispatcher // An AdviceDispatcher object, which will be further discussed below
);

exception(
	method,	// The method that triggered the advice
	args,	// The arguments passed into the method (struct)
	target,	// The bean that contains the method that triggered the advice
	error	// The cfcatch struct for the error
);

While you are not required to define the arguments (you might not need one or more), if you do define them be sure to spell them right because they are passed as named arguments, not numbered.

Now, the around() method is special because it receives a single object, AdviceDispatcher, which is essentially the same as the MethodInvocation object in ColdSpring. This object gives you full control over what will happen with your method call. Within your around device, you can trigger the target method execution by calling the run() method of the AdviceDispatcher object. Beyond that, you can put any code you want around it, to define code to run before and after. Your code can also make it so the method will not run in certain situations, all you have to do is create a situation where the AdviceDispatcher.run() method does not run. Here is the definition of the AdviceDispatcher object:

lighwire.aop.AdviceDispatcher
METHOD		RETURN TYPE	DESCRIPTION
run()		void		Executes the target method
getTarget()	object		Returns the target bean object
getMethod()	string		The name of the target method
getArguments()	struct		The arguments passed to the target method

That’s it! This is pretty much all you need to know to do AOP with Lightwire. Now I do realize that this article assumes prior knowledge of Lightwire and AOP, so I’m hoping to blog some tutorials on both of those topics to make things clearer for those just getting started with those.

I’ve been talking with Peter Bell and if my changes prove to be any good, which I hope they will, they could eventually make it into the core product on riaforge. For now, you can download my modified Lightwire by clicking the link at the bottom. I’ve included an aopSample folder where you can see some tests. They’re not the best and just output text, but it’s better than nothing for now. You can unzip the folder in your webroot, or you can unzip it anywhere on your web server and modify the component paths in the aopSample/index.cfm file. I’ve been testing this on CF 8, IIS, so if you run into problems and are running on a different platform let me know so I can get them sorted out.

DOWNLOAD LIGHTWIRE WITH AOP

Arbitrary runtime constructor dependencies in Lightwire
Saturday, March 6th, 2010

I love Lightwire for dependency injection, it’s lightweight, it’s not XML based, and allows for mixins which saves me from having to constantly add constructor properties or setters. However, I was recently confronted with a problem. When using Lightwire for transient beans, I often found myself wanting to inject dependencies, but also pass in some properties/dependencies at runtime (for example, some data somebody entered in a form). Now, an obvious way to do this would be to define the bean without that dependency, create a setter for it, and then add whatever you need to the bean using that. Somehow, it felt like kind of a roundabout way of doing it, so I figured I’d look for a way to be able to do it at the time of bean invocation. In terms of code, here’s what I was looking for:

myBean = application.lightwire.getBean("myBean", form.runTimeData, form.moreData);

INSTEAD OF

myBean = application.lightwire.getBean("myBean");
myBean.setRuntimeData(form.runTimeData);
myBean.setMoreData(form.moreData);

Note that you could also do the above with one setter that would set all the runtime data you want at once. Still, it’s an extra call, and that just bothers me to no end! So after some modifications to the Lightwire code I was almost able to do what I wanted, with a small caveat. I wasn’t able to use numbered arguments, had to settle for named arguments for now (though I’m still working on it). So right now I’m able to do this:

myBean = application.lightwire.getBean(
	objectName="myBean",
	runTimeData=form.runTimeData,
	moreData=form.moreData
);

I’m not 100% happy with it because I’d like to get it working with numbered argument and avoid all that typing, but the arguments/argumentCollection object is a weird one and I haven’t been able to swing that yet. Hoping I’ll come up with some sort of solution eventually (if anybody has some insights in the Java internals of argumentCollection and how to manipulate that, I’m all ears). But for now this works for me.

I’m interested in knowing if anybody else would find this feature useful, or if for any reason this would be bad practice and maybe I’m going about things all wrong. Again, I know it’s kind of a small nitpicky thing, but when you’re coding all day, small details make a big difference!