Archive for the 'ColdFusion' Category
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!

Making ColdFusion report fields stretch without messing everything up
Tuesday, April 24th, 2007

The ColdFusion Report Builder was a welcome addition to CF, allowing for report generation without using third-party software like Crystal Reports. The problem with it is that documentation and examples are sparse. And the CFREPORT site doesn’t seem to have a lot of activity lately (in all fairness, I did not contact the site owner, maybe he’d have a solution for me). Granted, it’s not really that complicated to pick up, but there are some cases that leave you scratching your head. I recently ran into one such case.

Basically, the report builder allows you to put some fields on your report and you can make them a certain size. But what if you have text of variable size and you’re not sure how long it’ll be? No problem, you can just set it to whatever width you want and then set the “Stretch With Overflow” field to true. That way when the text is too long to fit within the pre-defined width it’ll wrap to the next line. That’ll solve all your problems, right? Nope…

This solution will work if your report is a simple table, with a single row of fields put one next to the other. If you have a field that requires more space, the text will wrap and push down thenext record. But what if you have something like the following?

Suppose the Office field got long and you set its “Stretch With Overflow” property to true, guess what would happen? Yeah, the text would wrap alright, but it wouldn’t push the stuff below it down, instead it would overlap it, and that’s obviously not good. I searched around and didn’t really find an answer to my problem. So either I didn’t search enough and wasted my time with a hack when there’s a built-in solution, or else I’m very clever and came up with a brilliant hack. I hope the latter is true!

I figured the way to make things stretch properly would be to put things in different bands. But you can’t randomly insert bands. So to get an extra band, we need a hack. I did it using groups. Basically, whenever you add a group you get a new band for that group. So my idea was to add groups on a field that is unique. That way you get extra bands but they actually aren’t grouping anything. I just used the primary key of my records as the group by field. And to be able to get more bands, I modified my query and to something like this:

SELECT
	JournalID,
	JournalID AS StretchHack1,
	JournalID AS StretchHack2,
	...
FROM Journals

Then you go under “Report > Group Management” and use those fields for Groups. You can put in as many groups as you need bands and then break down your fields/labels into the different bands. Here’s the result for my example:

I set the “Stretch With Overflow” property to true for Office, Contacts, Categories, and text. Because they are all in separate bands, if their content is too long to fit on one line it’ll wrap to the next line and push down the content below. Neat huh?

I’m sure this is not a bulletproof solution and there are certain types of layouts where this might either not work or be a real pain in the ass to use. But I think it should come in handy in cases resembling the one I illustrated above.