Wednesday, August 31, 2011

ColdSpring Setter Injection versus Constructor Arguments Snafu

I was troubleshooting an issue a colleague of mine was having the other day, where to his credit he was following best practices but it shot him in the foot. Wanted to mention it here quickly.

Most times when you are injecting a bean into another bean in ColdSpring you will use setter injections. They look like:

<bean id="bean1" class="com.nictunney.Bean1"/>

<bean id="bean2" class="com.nictunney.Bean2">
  <property name="Bean1">
    <ref bean="Bean1"/>
  </property>
</bean>

Bean2 defines a mutator (setter) method, setBean1(). ColdSpring will inject the Bean1 into Bean2 when Bean2 is created by explicitly calling Bean2.setBean1(bean1). This is a best practice when performing dependency injection to prevent circular dependencies.

So the problem we were encountering in code was that the Bean2 constructor was calling a method that relied on the Bean1 property, which was of course undefined during the instantiation. It took a little while to track this down as this was a Model-Glue subapplication with lots of other stuff that could have been creating the error.

So, the lesson learned is to remember how ColdSpring and DI works. ColdSpring is going to create an instance of a bean, call the bean's constructor and then perform any necessary setter injections. It all makes perfect sense, except when you least expect it ;)

The answer in this case was to determine if a circular dependency would occur, which in our case it wouldn't, and instead inject the dependent bean via a constructor argument like this:

<bean id="bean1" class="com.nictunney.Bean1"/>

<bean id="bean2" class="com.nictunney.Bean2">
  <constructor-arg name="bean1">
    <ref bean="Bean1" />
  </constructor-arg>
</bean>

In the constructor call setBean1(arguments.bean1).

Wednesday, August 24, 2011

Are you ColdFusion Curious?

There is always lots of buzz about Adobe ColdFusion across social networking channels from developers. Most of it is positive, but ColdFusion also takes some abuse from programmers who have not used it. This criticism then gets met with some pushback from well-meaning CF developers, which in turn makes the bulk of us look like rabid loyalists.

Unfortunately for those scouring for information on language pros or cons, many of the negative statements are misinformed, heresy, and some of it is just good-natured ribbing (which I encourage as I do the same). I'd like to challenge all of you who use a web development language like Ruby, PHP, C# and ASP to take a single hour and attend one of the Adobe ColdFusion Developer Week sessions and challenge yourself to check out CF and see just how productive it can be. Don't worry, I won't tell any of your friends you were there ;)

Sunday, August 14, 2011

Android Mobile Application Connection Issues with Flash Remoting and ColdFusion

I was debugging an application tonight that uses Flex to connect an Android mobile application to ColdFusion via Flash Remoting. Every time I tried to call the remote method via the RemoteObject I got the message:

Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed

So I checked my LAN settings and then played around with my Mac firewall control panel. It was disabled so I was baffled. I then came across this post that hinted that it could be my usage of the CheckPoint VPN-1 SecureClient. Disabling and closing the client had no effect, so eventually I figured out I had to just disable the security policy (Tools > Disable security policy). I hope this helps someone out there from ruining an otherwise perfectly good evening of coding!

Wednesday, August 10, 2011

Dear ColdFusion Team: Please fix this stuff in Zeus

I love ColdFusion. I've built a 13 year career out of it (so far). I want to see CF continue to be a great language. Here are a few things I see that need to be addressed:

1. Shorthand for creating structures
This is one of those things that I'm not sure how it got put into the language, but lets fix it now before it becomes one of those embedded issues we just have to accept for version after version like 1 based array indices (more on that later). Fix it now!

// current
myStruct = {key="value"};

// suggested
myStruct = {key:"value"};

2. Arrays should be zero-indexed
This is one I've mentioned on for years. The standard across every other language is to use zero based indices. Why CF didn't do this from the get-go is an enigma to me. It is a PITA and requires a different sort of looping criteria as well as a different sort of index allocation during creation (unless you are using arrayAppend()). I would like to suggest making this backwards compatible by offering an application level variable that will permit you to enable the old 1 based indices while you are converting apps or maintaining legacy apps.

3. Looping over Arrays (item versus index)
This is a biggie that was discussed on other blogs recently. When I loop over an array in tags I do this:
<cfloop array="#myArray#" index="item">

This makes no sense. An index is just that, the current array index you are looking at. In CF this actually returns the item specified by the current index. I cannot get the current index without searching my array. The correct way to implement this would be to allow the user to specify either attribute. This would also prevent the user from having to track the index via an incrementer. I have had to do this frequently when trying to match up the current array with another array with related data.

<cfloop aray="#myArray#" index="i" item="item">

In this loop index would refer to the current index, and item would refer to the current item - makes sense right?

4. Looping over queries in CFScript
The way to do this currently is to loop from 1 to qry.recordCount. This isn't terrible, however I'd like to see this updated as such:
for ( row in myQuery ) {
}

The same could be said for an array loop.
for ( item in myArray ) {
}

5. Clean up object functions
Let's catch up with other languages on this one. len(), arrayLen() etc. Instead, I should be able to use a variable.length function regardless of the type (string or array). Also arrayAppend() (myArray.push()), arrayGetAt() (myArray.getAt(), myArray.pop()), listAppend() (myList.addItem()), etc. There are tons of them that should be addressed. You don't need to do anything but deprecate these existing functions for a few versions.

6. Query() object
Well, this one is tricky, as I've been trying to come up with a better way of handling this myself. Going back to the early days of ColdFusion (back when we called it Cold Fusion ;) ) the initial selling point of the language was the ability to interact easily with databases. This was so much the case that IIRC the tag was actually prefaced db and not cf! is a very simple way to access queries, and I continue to use it as opposed to its script counterpart. In fact, this is so much the case that I have to write my DAOs in tag based syntax instead of using script, which would be preferred.

I'm not going to go into all the reasons I dislike the current script based query syntax, but my biggest issue currently is with how query params are assigned. I'd recommend this approach:

var myQuery = new Query({
sql: "SELECT col from table where id = new queryParam({value: arguments.id, cfsqltype: 'CF_SQL_VARCHAR'})",
datasource: application.dsn
});

Having to use a Query object is also a bit frustrating although I think I can just tack execute().getResult() onto the statement above, but I'd have to check. It would be much easier to wrap the query object and have it call a query function, which in turn would function just like cfquery:

var myQuery = query(sql="SELECT col from table where id = new queryParam({value: arguments.id, cfsqltype: 'CF_SQL_VARCHAR'})", datasource: application.dsn);

Those are some initial thoughts for ColdFusion syntax changes. Please feel free to post your own in the comments below.

Sunday, August 7, 2011