Thursday, December 24, 2009

CF9: One Difference Between the New Ternary Operator and IIF()

When I first saw the ternary operator in java, I confess I did not like it. To my way of thinking, it was odd and cryptic, and I did not see the advantage over a standard if/else statement. Well, I have come a long way. For simple comparisons I now prefer its sleeker syntax over the more bulky if/else construct.


So it was quite pleasing to see the ternary introduced in ColdFusion 9. I never much cared for the IIF() function. (Too reminiscent of MS Access I suppose) But stylistic preferences aside, I just noticed the behavior of the ternary operator differs from IIF() in another sense. It uses delayed evaluation.

Take this silly example. When someCondition is true, only the variable foo is defined.

   <cfset someCondition = true />
<cfif someCondition>
<cfset foo = 123>
<cfelse>
<cfset foo = 321>
<cfset bar = 88>
</cfif>


If you are using the new ternary operator, a statement like the one below would succeed. It does not matter that the variable bar is not defined. Because the second variable is only evaluated when someCondition is false.
 
<cfset result = someCondition ? foo : bar />

However, using IIF(), both variables are evaluated immediately, whether they are used or not. So this code would result in an error: "variable BAR is undefined"

 
<cfset result = IIF(someCondition, foo, bar) />
To avoid the error you would need to use the DE() function, which just feels awkward to me.

<cfset result = IIF(someCondition, foo, DE("bar")) />

So in this sense at least, the ternary operator is a bit smarter than the old IIF() function.

...Read More

Wednesday, December 23, 2009

Merry Christmas To All

I just wanted wish everyone in the CF community a Merry Christmas. I hope you all have a wonderful holiday. See you next year!

(My favorite holiday tune)


Why NORAD Tracks Santa

...Read More

Tuesday, December 22, 2009

Wrap and Scale Text (The Ghost of Code Past)

A long time ago, I wrote a cfc for wrapping and scaling image text to fit within a given set of dimensions. I always thought it was something better done in java. Well, I finally got around to creating a java version, and it is a lot simpler to use. I also improved the algorithm used to auto-scale the text, and may write up an entry on that later. Plus I finally added support for line breaks (left-to-right text only).




Options:

Alignment: Supports left, right or center alignment
Antialiasing: Enable or disable text anti-aliasing
AutoScale: Enlarge or reduce text size to best fit the text within the given area
DrawText: Enable or disable text drawing (Could be used for measuring only)
Font: Supports custom font name, style or size
Color: Supports custom text color
Ignore Margin: (Experimental) Ignores top and bottom padding on first/last line of text for a better text fit
Increment: Supports fractional font sizes and custom incrementing

It works very well for small to moderate amounts of text. Out of curiosity, I did test it with about 62,000 characters. (Crazy, I know). While it did work, it took a while. So if you are thinking of trying to calculate the font size needed to print War and Peace on a matchbook cover, think again. It is just not designed for that kind of volume.

Anyway, I tried to make the library as flexible as possible. So for example, you could wrap text without auto-scaling. You could also get the measurements of the wrapped text without actually drawing it onto your image. (I am not sure there is a need for this. But if you wanted to do it, you could!).

Next up, I am thinking of wrapped text with mixed styles (...I do love a challenge)

Source: wrapImageText-0.1a.zip


Update 2009-12-22: Fixed wrong file version in source

...Read More

Wednesday, December 16, 2009

ColdFusion + Tomcat + Apache + Windows (Take the plunge)

For a while now I have wanted to experiment with other CF engines. But kept putting it off for various reasons. Well, this weekend I decided to take the plunge. My first attempt was using CF9's multi-server install with JRUN which met with only partial success. For whatever reason I was never able to get the Open BlueDragon WAR file to deploy correctly under JRUN.

Thanks to a suggestion from Peter J. Farrell, I decided to try using Tomcat instead. Surprisingly, it was very simple to setup. I followed some excellent posts by Todd Rafferty and Matt Woodward and now have all three engines up and running with Tomcat + Apache on windows (.. and yes Todd, it is very fast!). Now be warned, Matt's entry is long. But it is very informative, so read it all. (Besides, if you read my blog I know you are used to long entries.)

Now I am busily reading up on Tomcat and Apache, wondering why I did not do this sooner...


Update: When I installed Tomcat I selected a different JVM than the one that ships with CF9. So the first time I tried to invoke a web service CF threw an error saying the "...class file has wrong version 49.0, should be 48.0". In case you run into this issue, it was easily solved after reading a handy post by Rupesh Kumar: ColdFusion and WebService : "class file has wrong version. Note, after updating the tools.jar, I did have to stop and restart Tomcat for the change to fully take effect.

...Read More

Monday, December 7, 2009

OT: Easter Eggs

In a recent post on stackoverflow.com, member Sergii mentioned a ColdFusion easter egg. (Thanks Sergii!) Go ahead and feel smug if you already knew about it. If not, check it out. It is ... interesting.

While searching for others, I came across a few other fun ones. Not all CF-related of course. But there are definitely some strange and amusing ones out there.

Various Programs (source: www.stackoverflow.com)
http://stackoverflow.com/questions/397576/whats-your-favorite-easter-egg

JQuery *This one rocks!* (source: www.aliaspooryorik.com)
http://www.aliaspooryorik.com/blog/index.cfm/e/posts.details/post/136

Google (source: www.danvega.org)
http://www.danvega.org/blog/index.cfm?mode=cat&catid=CCF3C429-AE69-270C-3D2E62AA9CC59D70

RIA Unleashed : Boston Site (source: www.remotesynthesis.com)
http://www.remotesynthesis.com/post.cfm/announcing-ria-unleashed-boston
* See the P.S. at the bottom

...Read More

Friday, December 4, 2009

Fedex Web Services + createObject("webservice") == Migraine

A very long time ago, I wrote an entry on my novice struggles using the Fedex web services with createObject(). Though the entry shows I still had a lot to learn about web services, I still get occasional questions about it. In particular, about working with the Fedex web services and createObject(). So I will offer this advice to anyone looking to do the same - don't.

While ColdFusion definitely simplifies the process of working with web services, it is also not the best tool for every web service. Especially the more complex ones. If you have ever tried using the FedEx web services with createObject("webservice"), you know how painful it can be. They are extremely complex and deeply nested. So unless you miraculously hit on the right code the first time around, you are likely to waste a LOT of time trying to troubleshoot cryptic Axis error messages .. and the time you spend will not be fun.

So my recommendation is to try using SOAP + CFHTTP instead. The Fedex WSDL developer files include working SOAP samples. They will get you up and running much faster than trying to translate the java examples into CF code. An old entry on Russ Michaels blog has some good tips on working with SOAP. There is also a current project using the SOAP approach with the Fedex Rates Web Service, under the project name CFFedexRates. You could easily use it as a base for some of the other web services.

Take my word for it, you will be glad you did.

Update December 9, 2009:
For a version of CFFedexRates that is compatible with the Rate Service v7, see issue #2 http://code.google.com/p/cffedexrates/issues/detail?id=2


Update January 21, 2010:
The featured downloads section was updated to include a version compatible with Rate Service v7.

Update May 4, 2010:
For a version of CFFedexRates that is compatible with the Rate Service v8, see issue #4 http://code.google.com/p/cffedexrates/issues/detail?id=4

...Read More

Thursday, December 3, 2009

ColdFusion: Encryption Interoperability Issues (Beginner)

Recently, I have seen a few questions about encryption interoperability. The libraries used by ColdFusion (Sun JCE) are pretty standard. So for the most part, compatibility should not be issue. But it got me to thinking about some of the common pitfalls when trading encrypted data with external tools. While they may seem obvious to some of you, many of them were not at all obvious to me.


While I am certainly no expert on the subject, most of the issues I have encountered, or seen in various forums, tend to involve two things: cipher settings and encoding. Now I know that seems like a blatantly obvious statement. But it is the source of more problems than you might think.

Unfortunately, the ColdFusion documentation on the encrypt/decrypt functions is a bit sketchy in places. Now to a degree, the minimal documentation is understandable. Realistically it would require whole volumes to provide a comprehensive explanation of encryption. But there are a few key aspects of the encrypt/decrypt functions that I feel could really use some illumination. If only to help developers avoid some of the more common interoperability problems.

A prime example is the algorithm argument. Most examples you will see use simple names like AES or DESEDE. What is not immediately obvious is that those simple names are short-hand for several settings: the algorithm, cipher mode and padding scheme. When you use the short-hand name, ColdFusion applies the default cipher mode and padding scheme automatically. The defaults may vary depending on which algorithm you select. But in the case of AES the defaults are ECB and PKCS5Padding. (At least from what I can tell). So in other words, the algorithm values AES and AES/ECB/PKCS5Padding are equivalent. To specify a different mode or padding just change the algorithm value.

Now chances are the external tool you are working with probably does not use exactly the same defaults as ColdFusion. But once you are aware of the additional settings for the various algorithms, it is much easier to figure out how to align the results. You just need to ensure the settings on both ends match up.

Take C# for example. The defaults for the RijndaelManaged class are a bit different than ColdFusion's. For example, the default mode is CBC rather than ECB and the default key size is 256 bit. So exchanging values between the two may not work right off the bat.

                    ColdFusion            C# (RijndaelManaged)
Mode: ECB CBC
Padding: PKCS5Padding PKCS7
Key Size: 128 bit 256 bit
Block Size: 128 bit 128 bit
Allowed Key Lengths 128, *192, *256 bit 128, 192, 256 bit

* Note: Unlimited encryption is required in CF for keys larger than 128 bit

Once you have aligned the cipher settings, double check the encoding used on the various values. In ColdFusion the string to be encrypted/decrypted "is always interpreted as a UTF-8 string". From what I observed, the key value seems to be interpreted as base64. So using this collective information you can now easily adjust the settings of ColdFusion and C# to produce the same results.
<!---
Encrypt/Decrypt
---->
<h3>ColdFusion (AES/CBC/PKCS5Padding) + iv</h3>

<cfset thePlainData = "Nothing to see here folks" />

<cfset theKey = generateSecretKey("AES", 128) />
<cfset theAlgorithm = "AES/CBC/PKCS5Padding" />
<cfset theEncoding = "base64" />
<cfset theIV = BinaryDecode("7fe8585328e9ac7b7fe8585328e9ac7b", "hex") />

<cfset encryptedString = encrypt(thePlainData, theKey, theAlgorithm, theEncoding, theIV) />
<cfset decryptedString = decrypt(encryptedString, theKey, theAlgorithm, theEncoding, theIV) />


<!---
Display results
--->
<cfset keyLengthInBits = arrayLen(BinaryDecode(theKey, "base64")) * 8 />
<cfset ivLengthInBits = arrayLen(theIV) * 8 />
<cfdump var="#variables#" label="AES/CBC/PKCS5Padding Results" />



using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace AESTest
{
public class AESCBC
{
public static void Main()
{
try
{
// Just hard coded values for testing ...
// MUST change them to match the values used in the CF code
String thePlainData = "Nothing to see here folks";
String theKey = "oRJUjgbx9SGGR6v3T8JGJg==";
String theIV = "f+hYUyjprHt/6FhTKOmsew==";
String encryptedText = EncryptText(thePlainData, theKey, theIV);
String decryptedText = DecryptText(encryptedText, theKey, theIV);

Console.WriteLine("Encrypted String: {0}", encryptedText);
Console.WriteLine("Decrypted String: {0}", decryptedText);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}

Console.ReadLine();
}


public static String EncryptText(String Data, String Key, String IV)
{
// Extract the bytes of each of the values
byte[] input = Encoding.UTF8.GetBytes(Data);
byte[] key = Convert.FromBase64String(Key);
byte[] iv = Convert.FromBase64String(IV);


// Create a new instance of the algorithm with the desired settings
RijndaelManaged algorithm = new RijndaelManaged();
algorithm.Mode = CipherMode.CBC;
algorithm.Padding = PaddingMode.PKCS7;
algorithm.BlockSize = 128;
algorithm.KeySize = 128;
algorithm.Key = key;
algorithm.IV = iv;

// Create a new encryptor and encrypt the given value
ICryptoTransform cipher = algorithm.CreateEncryptor();
byte[] output = cipher.TransformFinalBlock(input, 0, input.Length);

// Finally, return the encrypted value in base64 format
String encrypted = Convert.ToBase64String(output);

return encrypted;
}

public static String DecryptText(String Data, String Key, String IV)
{
// Extract the bytes of each of the values
byte[] input = Convert.FromBase64String(Data);
byte[] key = Convert.FromBase64String(Key);
byte[] iv = Convert.FromBase64String(IV);


// Create a new instance of the algorithm with the desired settings
RijndaelManaged algorithm = new RijndaelManaged();
algorithm.Mode = CipherMode.CBC;
algorithm.Padding = PaddingMode.PKCS7;
algorithm.BlockSize = 128;
algorithm.KeySize = 128;
algorithm.Key = key;
algorithm.IV = iv;

//FromBase64String
// Create a new encryptor and encrypt the given value
ICryptoTransform cipher = algorithm.CreateDecryptor();
byte[] output = cipher.TransformFinalBlock(input, 0, input.Length);

// Finally, convert the decrypted value to UTF8 format
String decrypted = Encoding.UTF8.GetString(output);

return decrypted;
}
}
}

Hopefully these small tips will help someone else or at least keep them from pulling out their hair trying to coerce ColdFusion and some other tool into producing the same results.

...Read More

Wednesday, December 2, 2009

How to Move A Directory

The round-a-bout way to move a directory always slips through my brain like it is a sieve. So this one is a reminder to myself. Use <cfdirectory action="rename"..>, or in ColdFusion 9 use the sleeker DirectoryRename() function. Note, an error will occur if the destination directory already exists.

<cfset sourceDirec ="C:\docs\images\20091202">
<cfset destDirec ="C:\20091202">

<cfdirectory action="rename"
directory="#sourceDirec#"
newDirectory="#destDirec#" />

...Read More

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep