tag:blogger.com,1999:blog-19737509477752625582009-07-11T06:59:04.908-04:00MXUnit Blog<a href="http://mxunit.org">MXUnit</a> is a unit test framework built by ColdFusion developers for ColdFusion developers. This represents some general rants and the like for project related stuff, unit testing, and CF in general.billyhttp://www.blogger.com/profile/06624894387927690246noreply@blogger.comBlogger107125tag:blogger.com,1999:blog-1973750947775262558.post-73065708930262570272009-07-10T05:00:00.007-04:002009-07-10T07:34:57.462-04:00A Generic ColdFusion Struct Visitor<div class="note">Warning: No unit tests accompany this code.</div> <p>Recently, I mentioned on Twitter that I wish CF had a regex version of <a href="http://www.cfquickdocs.com/cf8/#StructFindValue" target="_blank">StructFindValue</a>, and this started a conversation between me, <a href="http://www.bennadel.com/" target="_blank">Ben Nadel</a>, and <a href="http://www.mischefamily.com/nathan/" target="_blank">Nathan Mische</a>. Ben and Nathan, both of whom I swear are code factories, had code out there within hours to do what I was looking for. Bless their hearts. While I normally try to hold to the “Twitter is not a Chat” maxim, in this case, I ran with it and it yielded fruit.</p> <p>During our conversation, what I came to realize was that I didn’t want just a reStructFindValue, what I wanted was a generic means of looping over structures and then “doing stuff” with each key that it encountered, as it walked recursively through a structure, no matter how deep/nested.</p> <p>Some of you may recognize this as the <a href="http://en.wikipedia.org/wiki/Visitor_pattern" target="_blank">Visitor pattern</a>. I tweeted thusly:</p> <p style="padding-right: 10px; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background-color: silver">@<a href="http://twitter.com/bennadel">bennadel</a> what ColdFusion really needs is a StructVisitor. With that, a man could do great things. <br /> <br /><a href="http://twitter.com/marcesher/status/2518131918">2:12 PM Jul 7th</a> from <a href="http://www.tweetdeck.com/">TweetDeck</a> <a href="http://twitter.com/bennadel/status/2517930099">in reply to bennadel</a></p> <p>Inspired by our conversation, and by the quick contributions of these two fine gents, I decided to take a quick stab at a basic implementation of some code, which I’ll call “StructEach.cfc” (Nathan called his version StructEach, and I liked it). It should behave like so:</p> <ul> <li>Take a Struct and a Visitor object as arguments to an “each()” function </li> <li>Loop over all keys in the input Struct, recursing as it went </li> <li>For all keys in the struct, pass the key and struct value into the “visit()” function of the Visitor object </li> <li>The visit function of the Visitor must return a boolean indicating whether the code should continue looping over the struct </li> <li>The visit function of the Visitor can do whatever the hell it wants to do. </li> </ul> <p>Before showing the code for StructEach.cfc, let’s look at why you’d want to use something like this, and then how you would use it.</p> <p></p> <h2>Why? What are the use cases for this?</h2> <ul> <li>Perhaps you’d like to take a structure and convert it to XML </li> <li>Perhaps you’d like to do really weird or granular searching of the stuff inside the structure, even if the structure has arrays in it, queries, etc. </li> <li>Perhaps you’d like to “dump” the values of a struct, but you want them in textareas b/c you need to see exactly what the strings look like, whitespace and all </li> <li>Perhaps you’d like to do a deep comparison of two structures and report the differences in a way that’s easy to read </li> </ul> <p>That last one, by the way, is my own personal use case for MXUnit.</p> <h2>What Kind of Structures should it take?</h2> <p>For me, I wanted this thing to be able to handle nastiness, not just simple structures. At the very least, it should take a struct that was this ugly:</p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SlZEo6qktfI/AAAAAAAAAIg/DhFZKDONC6g/s1600-h/startstruct3.png"><img title="startstruct" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="244" alt="startstruct" src="http://lh6.ggpht.com/__j-6QTK4wT8/SlZEpYCehkI/AAAAAAAAAIk/nFIRvbblWYc/startstruct_thumb1.png?imgmax=800" width="141" border="0" /></a> </p> <h2>How do you use it?</h2> <p>First off, you’d write a CFC that implemented the “visit” function. Here’s a really simple visitor that just outputs anything passed into it, along with the full path to the value’s key in the structure</p> <p><strong>OutputVisitor.cfc</strong></p> <p></p> <pre class="cf" name="code"><br /><cfcomponent hint="" output="false"><br /> <cffunction name="visit" output="true" access="public" returntype="boolean" hint=""><br /> <cfargument name="key" type="string" required="true"/><br /> <cfargument name="value" type="any" required="true"/><br /> <br /> <cfif isSimpleValue(value)><br /> <cfoutput>#key# = #value# <br></cfoutput><br /> <cfelse><br /> <cfdump var="#value#" label="#key#" expand="true"><br /> </cfif><br /> <br /> <cfreturn true><br /> </cffunction><br /></cfcomponent></pre><br /><br /><p>You’d then use this visitor like so: </p><br /><br /><pre class="cf" name="code"><cfset outputVisitor = createObject("component","OutputVisitor")><br /><cfset runner = createObject("component","StructEach")><br /><cfset runner.each(struct,outputVisitor)><br /></pre><br /><br /><p>In the case of the sample struct shown above, you’d get this output: </p><br /><br /><p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SlZEpqdqHjI/AAAAAAAAAIo/cNOvoBv0h5U/s1600-h/outputvisitor%5B3%5D.png"><img title="outputvisitor" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="244" alt="outputvisitor" src="http://lh4.ggpht.com/__j-6QTK4wT8/SlZEp49iu8I/AAAAAAAAAIs/OL7LVTBS_Gw/outputvisitor_thumb%5B1%5D.png?imgmax=800" width="243" border="0" /></a> </p><br /><br /><h2>Where it gets interesting</h2><br /><br /><p>That’s not very useful, is it? But it demonstrates how you’d use it. What you can trust in your visitor is that for every key in the structure, your visit function will get called. That’s the sweetness of this approach… you’re free to do whatever you wish with the data coming in. </p><br /><br /><p>This gets interesting when you start to consider how this is all implemented: you’re passing an object into the StructEach… think about that. Objects can contain state. This means that you can “remember” things through the iterations of the struct, as your visit function is repeatedly hit. </p><br /><br /><p>Let’s look at an example that implements “regex find” functionality over a structure. My implementation will</p><br /><br /><ul><br /> <li>provide an init() function for taking in searchString and scope arguments </li><br /><br /> <li>return a struct containing keys “found”, “path”, and “value” as soon as it finds something that matches the regular expression, and it will return false so that the StructEach will stop searching. Consider this a findOneOf() > </li><br /><br /> <li>return an array containing multiple structs if scope is set to “all”. Consider this a findAll() > </li><br /></ul><br /><br /><p>You’d call it like this:</p><br /><br /><pre class="cf" name="code"><!--- a RegExFindVisitor that searches for 'even'; as soon as one is found, it'll stop searching ---><br /><cfset regexFindVisitor = createObject("component","RegExFindVisitor").init("even","one")><br /><!--- a RegExFindVisitor that searches for 'even' or 'ix'; it will search every key in the struct ---><br /><cfset regexFindAllVisitor = createObject("component","RegExFindVisitor").init("even|ix","all")><br /><br /><cfset runner.each(struct,regexFindVisitor)><br /><cfset runner.each(struct,regexFindAllVisitor)><br /><br /><cfdump var="#regexFindVisitor.getFound()#" label="regexFindVisitor"><br /><cfdump var="#regexFindAllVisitor.getFound()#" label="regexFindAllVisitor"><br /></pre><br /><br /><p>And here’s what you’d see:</p><br /><br /><p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SlZEp5JpiwI/AAAAAAAAAIw/u2HgHNiNy6A/s1600-h/regexfindvisitors%5B3%5D.png"><img title="regexfindvisitors" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="244" alt="regexfindvisitors" src="http://lh5.ggpht.com/__j-6QTK4wT8/SlZEqRHlb1I/AAAAAAAAAI4/PSJlVQO8qCo/regexfindvisitors_thumb%5B1%5D.png?imgmax=800" width="199" border="0" /></a> </p><br /><br /><p>This is all made possible because the Visitor object can provide any other functions that it wants to… as long as it has a “visit()”, nothing else matters. In addition, the object can retain state. Thus, as visit is called, it can store stuff inside of itself for later computation and retrieval. </p><br /><br /><p><strong>RegExFindVisitor.cfc </strong></p><br /><br /><pre name="code" class="cf"><cfcomponent hint="" output="false"> <br /> <br /> <cffunction name="init" output="false" access="public" returntype="any" hint=""><br /> <cfargument name="searchString" type="string" required="true"/><br /> <cfargument name="scope" type="string" required="false" default="one" hint="'one' or 'all'. If scope is 'all', returns an array; otherwise, returns a struct"/><br /> <cfset StructAppend(variables,arguments)><br /> <cfset variables.instance.found = []><br /> <cfreturn this><br /> </cffunction><br /> <br /> <cffunction name="visit" output="true" access="public" returntype="boolean" hint=""><br /> <cfargument name="key" type="string" required="true"/><br /> <cfargument name="value" type="any" required="true"/><br /> <cfset var tmp = ""><br /> <br /> <cfif isSimpleValue(value) && reFind(variables.searchString,value)><br /> <cfset tmp = {path=key,value=value,found="true"}><br /> <cfset ArrayAppend(variables.instance.found , tmp)><br /> <cfif variables.scope eq "one"><br /> <cfset variables.instance.found = variables.instance.found[1]><br /> <cfreturn false> <br /> </cfif><br /> </cfif><br /> <br /> <cfreturn true><br /> </cffunction><br /> <br /> <cffunction name="getFound" returntype="any"><br /> <cfreturn variables.instance.found><br /> </cffunction><br /></cfcomponent></pre><br /><br /><p>Note that our source structure contains keys that have arrays and queries in them, but we’re only concerned with the keys that have simple values (and any nested structs that have simple values). Consequently, I’ve wrapped the chunk of code that does the work in an “isSimpleValue()” check. </p><br /><br /><p>But imagine… what if you wanted to also search through the arrays or queries that are passed into this thing? You could do that by implementing some additional searches inside of here. </p><br /><br /><p>Here’s another one I whipped up: Imagine you had a big ugly struct with various and sundry data in it, and you wanted to get just the queries. </p><br /><br /><p>Here's how you'd call it: </p><br /><br /><pre class="cf" name="code"><cfset queryHarvester = createObject("component","QueryHarvester")><br /><cfset runner.each(struct,queryHarvester)><br /><cfdump var="#queryHarvester.getQueries()#"></pre><br /><br /><p>And here's its implementation:</p><br /><br /><p><strong>QueryHarvester.cfc</strong></p><br /><br /><pre class="cf" name="code"><br /><cfcomponent hint="" output="false"><br /> <cfset queries = {}><br /> <cffunction name="visit" output="true" access="public" returntype="boolean" hint=""><br /> <cfargument name="key" type="string" required="true"/><br /> <cfargument name="value" type="any" required="true"/><br /> <br /> <cfif isQuery(value)><br /> <cfset queries[key] = value> <br /> </cfif><br /> <br /> <cfreturn true><br /> </cffunction><br /> <br /> <cffunction name="getQueries" returntype="struct"><br /> <cfreturn queries><br /> </cffunction><br /> <br /></cfcomponent></pre><br /><br /><p>And here’s what you’d get</p><br /><br /><p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/SlZEqr_IV_I/AAAAAAAAAI8/H1lEMzqtEHo/s1600-h/queryharvestingvisitor%5B3%5D.png"><img title="queryharvestingvisitor" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="120" alt="queryharvestingvisitor" src="http://lh3.ggpht.com/__j-6QTK4wT8/SlZEqxG95jI/AAAAAAAAAJA/xYoyvDc51CQ/queryharvestingvisitor_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a></p><br /><br /><h2>How does it work?</h2><br /><br /><p>This is not sexy code, and it’s certainly not a) optimized or b) complete (for example, I’d like it to loop through arrays of structs as well). But it’s a start, and it’s very simple:</p><br /><br /><p><strong>StructEach.cfc</strong> </p><br /><br /><pre class="cf" name="code"><cfcomponent><br /> <cffunction name="each" output="true" access="public" returntype="any" hint=""><br /> <cfargument name="struct" type="struct" required="true"/><br /> <cfargument name="visitor" type="any" required="true"/><br /> <cfargument name="path" type="string" required="false" default="" hint="don't touch this, suckers"><br /> <cfscript><br /> var loopkey = "";<br /> var thisPath = arguments.path;<br /> <br /> for(loopkey in struct){<br /> thisPath &= "[ ""#loopkey#"" ]";<br /> if(isStruct(struct[loopkey])){<br /> each(struct[loopkey],visitor,thisPath);<br /> }else if(!visitor.visit(thisPath,struct[loopkey])){<br /> return;<br /> } <br /> thisPath = arguments.path;<br /> }<br /> </cfscript><br /> </cffunction><br /></cfcomponent></pre><br /><br /><h2>Final Thoughts</h2><br /><br /><p>This code, and even this approach, is purposely simple. There is nothing clever about it. I believe the value in an approach like this is in thinking about tasks in a more generic sense. Think of all the code out there in the world that does this: loops over keys in a structure recursively, and does stuff with the values it encounters. I imagine if you compared all of this code, it’d look remarkably similar in its recursion, but the details in the “else if” clause would be different. </p><br /><br /><p>Thus, in this approach, we’re extracting the common stuff into StructEach and providing hooks for implementations to get plugged into that “else if” part, in the form of a Visitor. Code gets much simpler and easier to understand; and code gets much easier to unit test because you’d be testing just your “visit” function, not the looping/recursion. </p><br /><br /><p>The downside is where you have recursion conditions that themselves require state external to the visitor; in this case, the StructEach approach wouldn’t work well, and there’s danger in trying to shoehorn an approach just to avoid a few lines of code. So, as with most things OO, you use this approach when it’s warranted, not just when it’s easy.</p><br /><br /><p>When you start thinking in more generic terms, you start to see opportunities for code reuse. For example, how much code is out there in the world, do you think, that loops over directories and "does stuff" to the directories and files in those directories? Imagine the dozen or so lines of boilerplate recursion code required to do the looping part, and the one line of code to delete the file. Multiply that by a gazillion. How much code in your own codebase does this looping, with the only difference being "what I do when I hit each file"?</p><br /><br /><p>If you think generically, you see there's a better way to do this: you create a DirectoryWalker type of deal that handles the looping, and then you provide a FileVisitor type of implementation that acts on each file it hits. So if you have code that deletes certain files in directories, or "touches" them to make them current, or archives certain files, or makes jpg thumbnails of pdfs that don’t already have thumbnails... you can separate that out into really small, easy-to-test Visitor implementations and just use DirectoryWalker to handle the boilerplate. </p><br /><br /><p>Consider the unit test for that last example, the one that generates thumbs. If you were to write a “generateThumbsForDirectory"()” function, that’s hard to test! Seriously… think about what would be required in a unit test to test it. You’re testing two things: 1) your recursion and 2) your thumbnail generation. But the recursion is boilerplate, and testing boilerplate sucks. What you really want to test is your thumb generation. So if you extract that out into a simple function that takes an existing File path, your job is simple: look for an existing thumb for that file, and if one doesn’t exist, create it. That’s a really small unit test comprising two functions: makeThumbnail_should_GenerateThumbnails_When_ThumbnailDoesNotExist() and makethumbnail_shouldNot_GenerateThumbnails_When_ThumbnailDoesExist(). You could write that in maybe 15 lines of code. You trust that the StructEach works because it’s been tested separately, and you can now trust your code because you’ve proven, with your tests, that your code works.</p><br /><br /><p><strong>Fewer lines of code + easier-to-test functions = fewer bugs.</strong></p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-7306570893026257027?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com6tag:blogger.com,1999:blog-1973750947775262558.post-61761945721398281212009-06-24T08:02:00.003-04:002009-06-24T08:06:52.426-04:00"Look, Ma. No Password!" - Secure Hashing in ColdFusion<span style="font-family:arial,sans-serif;">I soaked up tons of great stuff at </span><a href="http://www.thinksec.com/" style="font-family: arial,sans-serif;">Frank Kim's</a><span style="font-family:arial,sans-serif;"> recent </span><a href="http://www.sans.org/sansfire09/description.php?tid=1937" style="font-family: arial,sans-serif;">Sansfire 2009 training</a><span style="font-family:arial,sans-serif;"><br />in Baltimore. As a matter of fact, it was the single best training event I have ever attended and I highly recommend it. After the module on </span><a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html" style="font-family: arial,sans-serif;">Java Cryptography Architecture</a><span style="font-family:arial,sans-serif;"> (JCA) -- which was at the end of Day 3 and though my brain was fried -- I realized I had a big gap in my own knowledge in something that should be a fundamental skill for programmers today. Broadly and simply stated, that skill is to be able to protect data in your application. Now, if you're anything like me and you start hearing some terms like symmetric and asymmetric ciphers, MD5, SHA-1/2/3 message digest, cryptographically secure random number generation, etc., you might be inclined back away slowly (or quickly) and leave all that to someone else. Well, I'm here to say that implementing <a href="http://kb2.adobe.com/cps/546/e546373d.html" target="_blank">strong cryptography in ColdFusion</a> is a lot easier than I expected. And knowing how do this and why will give you valuable skills that can only make your software safer and your programming stronger.</span><br /><br /><span style="font-family:arial,sans-serif;">Let's start with a common web application task - storing credentials in a database. One appealing <a href="http://csrc.nist.gov/publications/drafts/800-118/draft-sp800-118.pdf">NIST recommendation</a> is that you <b>should</b> <b>not </b>store the passwords at all. Rather, you should store a <a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function" target="_blank"><i>secure hash</i></a> of the password instead. When authentication needs to take place, instead of reading the password from a database and comparing that to the password entered by the user, you retrieve the password hash from the database, hash the password entered in the form, then compare the hashes. If you understand why we do this and just want to see how, skip down to </span><span style="font-family:arial,sans-serif;"><b>Secure Hashing</b></span><span style="font-family:arial,sans-serif;">. If you're mumbling to yourself "That sounds like a fucking waste of time," read the next two paragraphs.<br /><br />The driver here is that passwords are secret and <u>nobody</u> should have access to a user's password other than the user. System administrators and support staff should have the ability to reset passwords but not to read them. You might ask, "But my sites don't contain any sensitive information, why should I care?". Though true, how much do you want to bet that users registered on your site are using the same set of credentials to log into other sites, even banks?<br />Does this possibly make your site a target for harvesting? Could this challenge customers' trust in you over time? Play that tape couple of times ...</span><br /><br /><span style="font-family:arial,sans-serif;">The good news is that password hashing is so simple I can see no real reason not to do it. I'm not claiming to make your site secure; I'm simply saying that if you securely store password hashes instead of passwords, you can mitigate a number of potential attacks; for example, the Rainbow Table attack [7].</span> <span style="font-family:arial,sans-serif;">Note that password hashing differs from storing passwords encrypted. Why is this important? Because anything encrypted needs to be <i>unencrypted</i> to be read. To unencrypt, there must be a key and frequently it will be one key that can be used to read all passwords. We don't <b>ever</b> want passwords to be read by <b>anyone</b><i>.</i> Period. So, we want to create a strong, secure, one-way hash. </span><br /><br /><span style="font-family:arial,sans-serif;"><b>Secure Hashing</b></span><br /><br /><span style="font-family:arial,sans-serif;">The technical term is <a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function%20" target="_blank">Cryptographic Hash Function</a>, and there are several algorithmic variations : most notably, Message Digest (<a href="http://en.wikipedia.org/wiki/MD5" target="_blank">MD5</a>), </span><span style="font-family:arial,sans-serif;">Secure Hash Algorithm</span><span style="font-family:arial,sans-serif;"> (</span><span style="font-family:arial,sans-serif;"><a href="http://en.wikipedia.org/wiki/SHA_hash_functions" target="_blank">SHA</a></span><span style="font-family:arial,sans-serif;">), and others. Essentially, a hash function generates a unique and fixed-sized representation of some data; aka a <i>Fingerprint</i>. A correct hash will always produce the same result for a given input; e.g., <i>f(x)=y</i>. For example, the string <i><span style="font-family:courier new,monospace;">foo</span></i>, when hashed with MD5 should always produce<span style="color: rgb(11, 83, 148); background-color: rgb(238, 238, 238);font-family:courier new,monospace;" > </span></span><span style="background-color: rgb(238, 238, 238); color: rgb(11, 83, 148);font-family:courier new,monospace;" >ACBD18DB4CC2F85CEDEF654FCCC4A4D8</span><span style="font-family:arial,sans-serif;"><span style="background-color: rgb(238, 238, 238); color: rgb(11, 83, 148);font-family:courier new,monospace;" > </span>in ColdFusion. If another algorithm is used, the output will be different than this, yet it still should always produce<br />consistent output. </span><br /><span style="font-family:arial,sans-serif;"><br />Now, what if there are users with the same passwords? Won't the hashes be the same in the database? Right you are. What a Rainbow Table</span><span style="font-family:arial,sans-serif;">[7]</span><span style="font-family:arial,sans-serif;"> is, is essentially a large list of passwords that have been hashed using a number of algorithms. The attacker compares the hashes in your database with the ones in his Rainbow Table and then finds the matching password. The solution to this is to create unique hashes using <i>salt</i> and to repeatedly hash the hash. Salting is the process of inserting random data into<i> </i>the original data. Then, we repeat the hashing about 1000 times. This creates a unique and, if done correctly, a more secure hash. </span><br /><br /><span style="font-family:arial,sans-serif;">Let's start with some usage. We use an example utility component ,<span style="font-style: italic;">Crypto</span> , to perform the hashing. Full source code can be found <a href="http://github.com/virtix/cfcrypto/tree/master">here</a>.</span><br /><br /><script src="http://gist.github.com/135191.js"></script><br /><span style="font-family:arial,sans-serif;">When run, this generates a <i>password hash</i> that looks something like <span style="color: rgb(11, 83, 148); background-color: rgb(238, 238, 238);font-family:courier new,monospace;" >72C2CA24AD19EF7A8A9FC89184BA17BFA2D65CF3BE4FD2F0BBF3B460BD123550BC2D6BAB3AADF76EEAA4D8B5F6641A73365B21D17158779468049CACC32F0F2E</span> and a base64 <i>secure random salt </i>value of <span style="color: rgb(11, 83, 148); background-color: rgb(243, 243, 243);">4OP5GFmp/z0YYgUUlprVoig4pkGWhNGgMl37Tn4sLPw=</span>. When a user creates or changes their password, store only the hash and salt:<br /><br /><script src="http://gist.github.com/135151.js"></script><br /></span><span style="font-family:arial,sans-serif;">Now, to authenticate a user, you do something like this:</span><br /><br /><script src="http://gist.github.com/135150.js"></script><br />We're simply comparing the hashed value of the password entered by the user to the hashed value stored in the database. We do this by first retrieving the salt from the database and using that to generate the <span style="font-family:courier new,monospace;">hashedFormPassword<span style="font-family:arial,sans-serif;"> value</span>.</span><span style="font-family:arial,sans-serif;"> </span><span style="font-family:arial,sans-serif;">If you've read this far, I'm sure you want to look under the hood:</span><br /><br /><script src="http://gist.github.com/135149.js"></script><br /><span style="font-family:arial,sans-serif;">It doesn't get much easier for a complex topic, does it?<span style="font-family:courier new,monospace;"> computeHash() </span>accepts 4 arguments:<i> password, salt, iterations, and algorithm</i>. The required ones are <i>password</i> and <i>salt</i> - <i>salt</i> should be a secure random base64 string. iterations is the number of times the hash will be rehashed. PKCS 5 recommends doing this "a modest" 1000 times[9]. This would be a performance concern if this operation were done frequently, but since it is done only when a user logs in or creates an account, it's considered acceptable. The last parameter, algorithm, is a specific message digest algorithm. It's specified here are SHA512, which is the strongest FIPS-140 approved secure hashing algorithm. Adobe has some very good <a href="http://%20http//www.adobe.com/devnet/coldfusion/articles/dev_security/coldfusion_security_cf8.pdf">documentation</a> on available security providers and other related security best practices - this is required reading for ColdFusion developers! [5]<br /><br /><b>Salt Generation:</b></span><br /><br /><span style="font-family:arial,sans-serif;">The core concept behind salt generation is to create a random set of bytes of N length. Since ColdFusion sits on Java, I chose the <span style="font-family:courier new,monospace;">java.security.SecureRandom</span> class.</span><br /><br /><script src="http://gist.github.com/135153.js"></script><br /><br /><b><span style="font-family:arial,sans-serif;">Summary</span></b><br /><br /><span style="font-family:arial,sans-serif;">Using the example <a href="http://github.com/virtix/cfcrypto/tree/master">Crypto</a> component or your own variation will give you a viable option to storing passwords directly in the database and contribute to better security in your application. However, <b>do not</b> take my word alone for this. Please do some thorough research and learn for yourself. When it comes to protecting your customer's data and privacy (and your job) make sure you know what you are doing and why.</span><br /><br /><span style="font-family:arial,sans-serif;">Test and be Happy!</span><br /><br /><b style="font-family: arial,sans-serif;">References (Many are PDFs):</b><br /><span style="font-family:arial,sans-serif;">[1] OWASP Java Hashing - http://www.owasp.org/index.php/Hashing_Java</span><br /><span style="font-family:arial,sans-serif;">[2] NIST Secure Hash Standard - http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf<br />[3] FIPS-140-2 Draft (June,18,2009) - http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf</span><br /><span style="font-family:arial,sans-serif;">[4] Guide to Enterprise Password Management (Draft) - http://csrc.nist.gov/publications/drafts/800-118/draft-sp800-118.pdf</span><br /><span style="font-family:arial,sans-serif;">[5] ColdFusion 8 developer security guidelines - http://www.adobe.com/devnet/coldfusion/articles/dev_security/coldfusion_security_cf8.pdf</span><br /><span style="font-family:arial,sans-serif;">[6] Java Cryptography Architecture (JCA) - http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html</span><br /><span style="font-family:arial,sans-serif;">[7] Rainbow table - http://en.wikipedia.org/wiki/Rainbow_table</span><br /><span style="font-family:arial,sans-serif;">[8] NIST Advanced Encryption Standard Algorithm Validation List - http://csrc.nist.gov/groups/STM/cavp/documents/aes/aesval.html</span><br /><span style="font-family:arial,sans-serif;">[9] PKCS #5 v2.1: Password-Based Cryptography Standard - ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2_1.pdf</span><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-6176194572139828121?l=blog.mxunit.org'/></div>billyhttp://www.blogger.com/profile/06624894387927690246noreply@blogger.com4tag:blogger.com,1999:blog-1973750947775262558.post-54240538325018800552009-06-13T12:21:00.021-04:002009-06-13T14:17:40.012-04:00IntelliJ IDEA Plugin for CFML<div xmlns="http://www.w3.org/1999/xhtml">As <span class="blsp-spelling-error" id="SPELLING_ERROR_0">ColdFusion</span> developers, unlike many other languages, the one thing we simply don't have is code insight or object & method resolution for 3rd party Java or <span class="blsp-spelling-error" id="SPELLING_ERROR_1">ColdFusion</span> products. I understand that this is difficult to achieve for dynamic languages, but, just because it's "hard" is not an excuse, <span class="blsp-spelling-error" id="SPELLING_ERROR_2">imo</span>.<br /><br />I'm a big fan of <span class="blsp-spelling-error" id="SPELLING_ERROR_3">IntelliJ</span> IDEA and it's the best tool for Java and Groovy development I've used - these guys know what an <span class="blsp-spelling-error" id="SPELLING_ERROR_4">IDE</span> should do and they also support open source projects. IDEA also gives you the ability to create Flex and Air projects. Recently, developer Valeria <span class="blsp-spelling-error" id="SPELLING_ERROR_5">Nikolaenko</span>, has built a <span class="blsp-spelling-error" id="SPELLING_ERROR_6">CFML</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_7">plugin</span> for IDEA and has consistently been releasing updates. The <a href="http://coldfusion-in-idea.blogspot.com/2009/06/java-loader-completion.html">most recent one</a> fits especially nicely with any project that uses <span class="blsp-spelling-error" id="SPELLING_ERROR_8">ColdFusion</span> and Java together. Specifically, if you use Mark Mandel's <a href="http://javaloader.riaforge.org/" target="_blank"><span class="blsp-spelling-error" id="SPELLING_ERROR_9">JavaLoader</span></a> you'll find this feature of particular interest. Basically, it allows you to get Java method resolution inside of <span class="blsp-spelling-error" id="SPELLING_ERROR_10">CFML</span> for classes loaded with <span class="blsp-spelling-error" id="SPELLING_ERROR_11">JavaLoader</span>. Check it out:<br /><br /><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_R-2JPB8crqk/SjPshS7g0pI/AAAAAAAAAKY/C5bWfpmWm6A/s1600-h/ss1.png"><br /></a></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_R-2JPB8crqk/SjPtAgQeX8I/AAAAAAAAAKg/Tch6CKdlAtk/s1600-h/ss1.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="http://2.bp.blogspot.com/_R-2JPB8crqk/SjPtAgQeX8I/AAAAAAAAAKg/Tch6CKdlAtk/s320/ss1.png" alt="" id="BLOGGER_PHOTO_ID_5346877775533727682" border="0" /></a><br /><br /><div align="center"><div style="text-align: left;">So, what we've done here is create a <span class="blsp-spelling-error" id="SPELLING_ERROR_12">JavaLoader</span> instance using<span style="font-family:monospace;"> <span class="blsp-spelling-error" id="SPELLING_ERROR_13">createObject</span>(...) </span>and then we create a Java class, <span style="font-family:monospace;"><span class="blsp-spelling-error" id="SPELLING_ERROR_14">esapi</span></span>, in the editor. When you type <span style="font-family:monospace;"><span class="blsp-spelling-error" id="SPELLING_ERROR_15">esapi</span>.</span> then hit <span class="blsp-spelling-error" id="SPELLING_ERROR_16">Ctrl</span>+Space, <i>Voila!</i>, all the methods and their signatures for the <a href="http://www.owasp.org/index.php/ESAPI"><span class="blsp-spelling-error" id="SPELLING_ERROR_17">ESAPI</span></a> class are presented in the editor. You do have to perform a few project set up tasks in order to make this happen in IDEA, assuming you've installed the CFML plugin already:<br /></div><div align="left"><ol><li>Add your 3rd party jars to your project's class path</li><li>Add the <span class="blsp-spelling-error" id="SPELLING_ERROR_18">ColdFusion</span> facet to your project and tell it where your <span class="blsp-spelling-error" id="SPELLING_ERROR_19">webroot</span> and <span class="blsp-spelling-error" id="SPELLING_ERROR_20">subdirectory</span> are located</li><li>In your source code, tell the <span class="blsp-spelling-error" id="SPELLING_ERROR_21">CFML</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_22">plugin</span> about your <span class="blsp-spelling-error" id="SPELLING_ERROR_23">JavaLoader</span> variable and jar locations:<br /><span style="font-family:monospace;"><!---@javaloader name="loader" <span class="blsp-spelling-error" id="SPELLING_ERROR_24">jarPath</span>="/home/<span class="blsp-spelling-error" id="SPELLING_ERROR_25">webapps</span>/<span class="blsp-spelling-error" id="SPELLING_ERROR_26">cfesapi</span>/lib/" ---></span><br /></li></ol>If you've ever done Java development without code insight, you know what the typical process is - you need to constantly go back and forth between the <span class="blsp-spelling-error" id="SPELLING_ERROR_27">Javadoc</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_28">APIs</span>, copy and paste, or you dump out the object's <span class="blsp-spelling-error" id="SPELLING_ERROR_29">metadata</span> and try to figure out how to call it. The configuration above steps seem like minimal effort compared to the typical manual process required to work with Java inside of <span class="blsp-spelling-error" id="SPELLING_ERROR_30">ColdFusion</span>. It's not the end-all-be-all solution, but it's big step in the right direction. Ideally, if all the configuration could be done at the project level, that would even be better.<br /><br />Now, if we could just have an <span class="blsp-spelling-error" id="SPELLING_ERROR_31">MXUnit</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_32">plugin</span> for IDEA, it could be a seriously dangerous all-around <span class="blsp-spelling-error" id="SPELLING_ERROR_33">IDE</span> for $249 US.<br /></div><div align="left"><br /></div></div></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-5424053832501880055?l=blog.mxunit.org'/></div>billyhttp://www.blogger.com/profile/06624894387927690246noreply@blogger.com0tag:blogger.com,1999:blog-1973750947775262558.post-3263718143655266552009-06-04T05:00:00.001-04:002009-06-11T08:48:46.500-04:00Continuous Integration with Hudson, CF, and MXUnit: Setting up Notifications<p>In previous entries, I wrote about <a href="http://blog.mxunit.org/2009/05/continuous-integration-with-coldfusion.html" target="_blank">configuring a project in Hudson</a> and setting up your project to <a href="http://blog.mxunit.org/2009/05/ci-with-hudson-cf-and-mxunit.html" target="_blank">run your MXUnit tests and report results</a>. Before we talk about setting up email and IM communication, let’s briefly look at what you should now have, in pictures, if you’ve set up a project. I’m using MXUnit as the example project here.</p> <p>First, an entry in the project list, indicating the build’s health</p> <p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/SicZP9qSllI/AAAAAAAAAHA/pezbiUM_Gk8/s1600-h/hudson_mxunitbuildhealth%5B3%5D.png"><img title="hudson_mxunitbuildhealth" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="hudson_mxunitbuildhealth" src="http://lh5.ggpht.com/__j-6QTK4wT8/SicZQPgN92I/AAAAAAAAAHE/J_e3kwUOsRI/hudson_mxunitbuildhealth_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>Next, when you drill into the project, you’ll see your recent build results on the left, along with your test trends on the right</p> <p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/SicZQfDEwAI/AAAAAAAAAHI/TKRCYsMOKsw/s1600-h/mxunit_projectstatus%5B3%5D.png"><img title="mxunit_projectstatus" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="mxunit_projectstatus" src="http://lh3.ggpht.com/__j-6QTK4wT8/SicZQvcxNuI/AAAAAAAAAHM/m_fNU9Fdd-Q/mxunit_projectstatus_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>On the left side, with your list of previous builds, you can click the “trends” link and see a time trend graph</p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/Sim3ljYCQCI/AAAAAAAAAIA/cJrVLfdmw_Q/s1600-h/hudson_timetrend%5B3%5D.png"><img title="hudson_timetrend" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="118" alt="hudson_timetrend" src="http://lh6.ggpht.com/__j-6QTK4wT8/Sim3lyCt_aI/AAAAAAAAAIE/R0JBwXlhFEo/hudson_timetrend_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>You can click on a link for your last build and see more details about it. When you click on the Test Results link, you get this view</p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SicZQ9ZTPqI/AAAAAAAAAHQ/dD_9BkKqtLw/s1600-h/mxunit_passedbuild%5B3%5D.png"><img title="mxunit_passedbuild" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="mxunit_passedbuild" src="http://lh4.ggpht.com/__j-6QTK4wT8/SicZRLDAfPI/AAAAAAAAAHU/pz0AzHj9T50/mxunit_passedbuild_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>From there, you can drill down into the reports for more information, should you need it</p> <p>If a build fails, it’ll show you something like this:</p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SicZRcAxLDI/AAAAAAAAAHY/1ps_QIhUoyM/s1600-h/hudsonbuildfailure%5B3%5D.png"><img title="hudsonbuildfailure" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="hudsonbuildfailure" src="http://lh6.ggpht.com/__j-6QTK4wT8/SicZRoAYGlI/AAAAAAAAAHc/5EtF7oSUpjc/hudsonbuildfailure_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <h2>Communicating This Information</h2> <p>All of this information is lovely; however, we’re not interested in monitoring the Hudson interface every time a build runs. Instead, we want to get notified when things change. That’s it: <strong>when build status changes</strong>. For me, continuous integration is as much about communicating results as it is about providing an easy, scheduled mechanism for running your tests (we don’t care about compiling and linking in CF applications, so that core benefit of CI doesn’t apply to us either).</p> <p>Ideally, only interested parties would be notified on a change in build status. For example, let’s say a build runs at 8:00 AM, and all tests pass. It runs again at 8:15 AM, and tests fail. What I want to happen is:</p> <ol> <li>Hudson looks at source control for the users who have committed code since the last build </li> <li>Hudson notifies *just* those people that the build is now failing. </li> <li>Hudson does this either via email, instant message (SMS), or both. </li> </ol> <p>Fortunately, this is all possible. Let’s set it up.</p> <h3>Configuring Email Settings</h3> <p>From the main Hudson screen, type “configure” in the search box</p> <p>Scroll down to the bottom and find the E-mail notification section.</p> <p>I’m using gmail in this case, so I plugged in my gmail credentials, using “smtp.gmail.com” as the server. I’m keeping “default email suffix” blank since this can’t be computed (this would be more for corporate email accounts where you can trust that the email would end up as “firstname” + “lastname” + default email suffix, for example).</p> <p>In the Advanced settings, I checked “use smtp authentication”, entered my email address into the username field, added my password, checked “use ssl”, and specified the port as 465</p> <p> </p> <h3>Configuring SMS (Jabber) via GTalk</h3> <p>From the “manage Hudson” screen, click on Manage Plugins</p> <p>go to “Available Plugins”, and find the “Hudson Jabber notifier plugin”. Click things and install it. Restart if necessary.</p> <p>Now, back in your Manage Hudson screen, you’ll have a new section, right above the Email section, for Jabber.</p> <p>I entered my gmail address and password, and “talk.google.com” as the server. That’s it!</p> <p>For the visually inclined, here’s what all of this looks like:</p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SicZSXgxKtI/AAAAAAAAAHo/6rljg7wc3o8/s1600-h/hudsonnotificationsetup%5B7%5D.png"><img title="hudsonnotificationsetup" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="126" alt="hudsonnotificationsetup" src="http://lh3.ggpht.com/__j-6QTK4wT8/SicZSZZawuI/AAAAAAAAAHs/PEUCSMyQvNQ/hudsonnotificationsetup_thumb%5B3%5D.png?imgmax=800" width="244" border="0" /></a> </p> <h3>Noise Control</h3> <p>At the project level, you can also configure how noisy you want this communication to be. Here’s what that looks like:</p> <p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SicZRnuZjOI/AAAAAAAAAHg/HdEMwJmO6Ms/s1600-h/hudson_notificationconfig%5B3%5D.png"><img title="hudson_notificationconfig" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="135" alt="hudson_notificationconfig" src="http://lh5.ggpht.com/__j-6QTK4wT8/SicZSHFZwKI/AAAAAAAAAHk/gmcvSg-1QcY/hudson_notificationconfig_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>From that image, you’ll see that I can configure <strong>when</strong> <strong>I want to be notified</strong>… every build, just on change, etc. Thus, to substantially reduce the noise from your scheduled builds, go into the project and configure it to only notify via IM on status change. <strong>This, in my humble opinion, is gold.</strong></p> <h3>Configuring Users</h3> <p>Now that the communication mechanisms are set up, we have to associate email addresses with the subversion users. Quite possibly there’s an easier way to do this via some batch process, but as I’m just getting started with my Hudson investigation, I haven’t looked into it. So please don’t take this as “the only way” or “best practice”, because I do not know that to be true.</p> <p>For my setup for MXUnit, I linked it to SVN and when it updated and there were changes, it created new a new user for any user that was associated with a change. So, I committed some code to MXUnit, ran a Hudson build, and Hudson added me as a user, silently.</p> <p>To give the “marc.esher” user notification details:</p> <ol> <li>from the main Hudson screen I clicked on “people” then on “marc.esher”. (You can also get here if you know the username you want to configure by typing that username in the "Search” box at the top of the screen) </li> <li>click Configure </li> <li>enter my email address </li> <li>since I installed the Jabber plugin, it also has a space for jabber credentials. I entered my gmail address again. </li> </ol> <h2>So what’s all this get me?</h2> <p>After this configuration was finished, here’s what I get:</p> <p>Emails on build failure that look like this:</p> <p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SicZSiTZVnI/AAAAAAAAAHw/0tkvpf7sAHU/s1600-h/hudsonbuildfailure_email%5B3%5D.png"><img title="hudsonbuildfailure_email" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="164" alt="hudsonbuildfailure_email" src="http://lh5.ggpht.com/__j-6QTK4wT8/SicZSxsG-rI/AAAAAAAAAH0/pz6Sj_uhtxI/hudsonbuildfailure_email_thumb%5B1%5D.png?imgmax=800" width="244" border="0" /></a> </p> <p>GTalk notifications on build failure that look like this:</p> <p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SicZTM87_NI/AAAAAAAAAH4/Yiy9GrK_eNI/s1600-h/hudsonbuildfailure_gtalk%5B2%5D.png"><img title="hudsonbuildfailure_gtalk" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="229" alt="hudsonbuildfailure_gtalk" src="http://lh6.ggpht.com/__j-6QTK4wT8/SicZTO-Oh6I/AAAAAAAAAH8/futk3I4-Ai4/hudsonbuildfailure_gtalk_thumb.png?imgmax=800" width="244" border="0" /></a> </p> <p></p> <p>And corresponding messages for when things go back to normal.</p> <p>Importantly, <strong>what I don’t get</strong>: noise. I don’t get notified on every build via email. I don’t have to constantly go to a website to check the build status. I get notifications when I care about them: when things go bad, and when things go from bad back to good.</p> <h2>Summary</h2> <p>Continuous Integration is about communication. It’s about noise control. And so far I’m discovering that Hudson is performing admirably. You can configure different methods of communication, all hooked into source control, with different “strategies” (on every build, on every change, etc). I appreciate this level of configurability. In addition, I was able to get all of this going without reading a single page of documentation. I think that speaks to Hudson’s ease of use.</p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-326371814365526655?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com1tag:blogger.com,1999:blog-1973750947775262558.post-21374759916411486962009-05-31T00:44:00.034-04:002009-05-31T22:56:06.100-04:007 Totally Stupid Useless Ways to Invoke ColdFusion Components<div align="center"><img src="http://lh6.ggpht.com/_R-2JPB8crqk/SiHldA0ABMI/AAAAAAAAAJk/Zk5parmjrQA/%5BUNSET%5D.png?imgmax=800" style="max-width: 800px;" /><br /></div><br /><br /><br /><br /><br /><div align="center"><span style="color: rgb(204, 0, 0);"><b>Warning</b></span>:<br />The content contained herein contains utterly useless, potentially offensive, and very juvenile language. This is not suited for just about everyone.<br /></div><br /><p><br />There are many levels of stupidity - I believe in, and have worked very hard at, exploring many such levels in theory and in practice. Though some individuals are gifted with natural stupidity, I believe to be a true and utter mooncalf demands rigorous discipline and hours of practice. To support this process, you can explore other distinct facets of stupidity ranging from the simple-moron to the mullet-sporting-crank-snorting-utter-fucking-bonehead. To be more than a mere journeyman dolt, however, demands discipline and, above all, dedication.<br /></p><br /><br /><p><br />In this small and inane piece, I will attempt to demonstrate how a programmer can proceed from a state of being simply moronic to a high level random-self-inflicted-headwound-fuckhead. The key lies is in using what little brain power you might have towards something of little or no utility whatsoever. Remember this and I truly believe you will go nowhere but backwards.<br /></p><br /><br /><div style="font-weight: bold; font-size: 16px;" align="center"><br />7 Totally Stupid Useless Ways to Invoke ColdFusion Components<br /></div><br /><p align="center"><br />Full stupid source code available <a href="http://github.com/virtix/7stupidthings/tree/master">here</a><br />(click the Download button for a zip/tar file)<br /></p><br /><p><br />This is the stupid component under test we will invoke in 7 truly dumb ass ways.<br /><script src="http://gist.github.com/120734.js"></script><br /></p><br /><br /><br /><p>All these examples are written as MXUnit tests, which, by doing so, has arguably decreased my own stupidity rating. Note also that these are written in <code style="font-size: 13px;"><cfscript></code>. This reduces the number of keystrokes required in order to write useless piss-ant code.<br /></p><br /><br /><br /><strong>Here's the <code style="font-size: 13px;">setUp()</code></strong>:<br /><br /><script src="http://gist.github.com/120735.js"></script><br /><br /><span style="font-weight: bold;">#7 (Simply Moronic)</span><br /><br /><script src="http://gist.github.com/120743.js"></script><br /><br /><span style="font-weight: bold;">#6 (Approaching Idiocy)</span><br /><br /><script src="http://gist.github.com/120747.js"></script><br /><br /><span style="font-weight: bold;">#5 (The Java Loser)</span><br /><script src="http://gist.github.com/120748.js"></script><br /><br /><br /><span style="font-weight: bold;">#4 (Douche Bag)</span><br /><script src="http://gist.github.com/120749.js"></script><br /><br /><span style="font-weight: bold;">#3 (Turd Mongrol)</span><br /><script src="http://gist.github.com/120753.js"></script><br /><br /><br /><span style="font-weight: bold;">#2 (Dumbass Pissant)</span><br /><script src="http://gist.github.com/120751.js"></script><br /><br /><br /><span style="font-weight: bold;">#1 (Asshat Monkey Shit Hurler)</span><br /><script src="http://gist.github.com/120754.js"></script><br /><br /><br /><p>Stupid source code <a href="http://github.com/virtix/7stupidthings/tree/master">here</a></p><br /><p><br /></p><br />Feel free to post stupid code or links to such. Using <a href="http://gist.github.com/gists">Gists</a> might be cool, though they're not stupid.<br /><p><br /></p><p><br /></p><p><br /></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-2137475991641148696?l=blog.mxunit.org'/></div>billyhttp://www.blogger.com/profile/06624894387927690246noreply@blogger.com8tag:blogger.com,1999:blog-1973750947775262558.post-42592181684970297602009-05-29T05:00:00.001-04:002009-05-29T22:27:27.763-04:00CI with Hudson, CF, and MXUnit: Configuring ANT and Running Tests<p>If you’re already running your MXUnit tests with ANT, then this should go quickly. If not, then you’ll need to <a href="http://mxunit.org/doc/index.cfm?doc=antjunit">read this first</a>. Create your ANT build file (build.xml), create your “runTests” target (or whatever you want to call it), and get your test runs working from within Eclipse or at the command line. Only after you get those working should you try integrating with Hudson… one thing at a time.</p> <h2>Configuring ANT within Hudson</h2> <p>Hudson needs to know where your ANT install lives. If you haven’t downloaded ANT, do so now, unzip it, and put it somewhere. Then, copy the path to that location.</p> <p>From your main Hudson screen, click on “Manage Hudson”, then “Configure System”. More quickly, type “configure” into the search box and it’ll take you to the same place. Go down to the “ANT” section, click “Add”, and paste that path to your ANT install. Note, this is NOT the “bin” directory… just the ANT root. Give it a name, like “ANT 1.7” or whatever. Click Save</p> <p><strong>Hudson will not treat this ANT location as the default location</strong>. You must (at least, I did) have to explicitly choose this ANT instance for every project setup. Just so you know. This tripped me up at first.</p> <h2>Sample ANT build file</h2> <pre class="cf" name="code"><br /><br /><?xml version="1.0" encoding="ISO-8859-1"?><br /><br /><project name="Sample" basedir="." default="main"><br /><br /> <target name="init"><br /><br /> <property name="testroot" location="../tests/framework" /><br /> <property name="componentPath" value="mxunit.tests.framework" /><br /> <property name="server" value="localhost" /><br /> <property name="port" value="80" /><br /><br /> <!-- wherever the mxunit-ant.jar lives --><br /> <property name="mxunitant" location="../ant" /><br /> <property name="mxunitjar" location="${mxunitant}/lib/mxunit-ant.jar" /><br /> <property name="mxunitxsl" location="${mxunitant}/xsl" /><br /><br /> <!-- this is where the xml and html will live --><br /> <mkdir dir="testresults" /><br /> </target><br /><br /> <target name="runtests" description="Make output directories and run the MXUnit task" depends="init"><br /> <taskdef name="mxunittask" classname="org.mxunit.ant.MXUnitAntTask" classpath="${mxunitjar}" /><br /> <mxunittask server="${server}" port="${port}" outputdir="testresults" verbose="true"><br /> <directory path="${testroot}" recurse="false" packageName="${componentPath}" componentPath="${componentPath}" /><br /> </mxunittask><br /><br /> <mkdir dir="junithtml" /><br /> <junitreport todir="junithtml"><br /> <fileset dir="testresults"><br /> <include name="*.xml" /><br /> </fileset><br /> <report format="frames" todir="junithtml" styledir="${mxunitxsl}" /><br /> </junitreport><br /> </target><br /><br /><br /></project></pre><br /><br /><h2>Configuring your project’s test runner step</h2><br /><br /><p>Navigate to your project, then click “Configure”. More quickly, you can search for your project by name, then search for “configure”, and you’ll get to the same screen.</p><br /><br /><p>Find the "Build" section. click "Add build step". Select "Invoke ANT". Select the ANT instance from the dropdown list of installed ANTs. In the "target" field, type the name of the target in your ANT build file that you use to run tests. For example, "runTests"</p><br /><br /><p>This <b>might</b> be all you need. so you could save this and try to do a build now, and see what happens.</p><br /><br /><h2>Test Runner Step Configuration, Part 2: Properties</h2><br /><br /><p>Now’s a good time to talk about the weirdo nature of ColdFusion projects with respect to CI. Remember, you checked out your project from Subversion into Hudson’s workspace, but that’s not the code you care about… your code already lives on a DEV server and is updated by some other means. However, there is one file that gets checked out that you do care about: Your ANT build file.</p><br /><br /><p>When Hudson runs your ANT file, it’ll be running the one from its workspace. And then that build file will be executing its tests against the components you specify on your DEV server. Got it? Good. Confused? I know.</p><br /><br /><p>It’s possible that your build file’s runTests target might need some properties that are possibly set in a properties file that you don’t keep in SVN or which otherwise you need to override. For example, for MXUnit itself, our build file looks at a file named “unames.properties” to get some configuration information such as server name, port, usernames/passwords, webroot location, and some other things. This is NOT kept in SVN b/c it’s unique for each MXUnit contributor. When MXUnit’s runTests is run, it tries to read that properties file and then set the server, port, and webroot properties. But since that file isn’t checked out from SVN, it’s not visible in Hudson’s workspace and thus those properties never get set. It’s super easy to get around this though!</p><br /><br /><p>In your ANT step’s “Advanced” tab, you’ll see a “properties” box. In here, you can type in any properties in name=value format, linebreak-delimited, and poof, properties problem solved. For example, here’s what I put into the properties box for the MXUnit job:</p><br /><br /><p>server=localhost<br /><br />port=80<br /><br /><br />webroot=c:/inetpub/wwwroot</p><br /><br /><h2>Configuring your project’s JUnit XML Output</h2><br /><br /><p>In that sample ANT build file above, you saw how easy it was for MXUnit to spit out JUnit-compliant XML. Basically, no matter where your tests actually run (<a href="http://blah/whatever/HttpAntRunner.cfc">http://blah/whatever/HttpAntRunner.cfc</a>), your JUnit XML files will go in a directory relative to the build file that is running. Got that? That means that, as discussed above, your JUnit xml files will go in your Hudson workspace somewhere. This is perfect, because that’s where Hudson wants them to be.</p><br /><br /><p>For example, with the MXUnit build, the build file is at mxunit/build.xml. It specifies a location for the JUnit xml output as something that evaluates to tests/testresults/tmp/. So in the Hudson configuration for the MXUnit job, I specify the JUnit XML location as:</p><br /><br /><p><strong>tests/testresults/tmp/*.xml</strong></p><br /><br /><p>That’s it. So wherever your xml files go relative to your workspace root, simply go to the “Post Build Action” section of your job configuration, check the “Publish JUnit XML” checkbox, and enter in the path to your xml files, with *.xml, as I did above. Click save</p><br /><br /><h2>Re-saving ant.bat</h2><br /><br /><p>After I got the MXUnit project all set up, I ran the build; it executed the tests; Hudson read the JUnit XML (all tests passed). And then…. Failed. Failed?! WTF? WTF was failing? The Hudson console output (thank you, Hudson!) read: “The system cannot find the batch label specified”.</p><br /><br /><p>This wasn’t a Hudson problem. It wasn’t an MXUnit problem. Turns out, it was the ant.bat file giving me grief. That’s right… the ant.bat that ships with the eclipse ANT install. Perhaps had I been using a “proper” install, this wouldn’t have been the case. Nonetheless, I wasn’t. So, how to fix it? Simple</p><br /><br /><p>Open up ant.bat in Textpad. Notice that it’s in Unix format. Change the format to “PC”. Click Save.</p><br /><br /><p>Rerun the Hudson build. Oh Joy. Oh Rapture. A fully functioning test run with test results. Let the CI begin.</p><br /><br /><h2>What’s Next?</h2><br /><br /><p>Next up, configuring notifications.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-4259218168497029760?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com0tag:blogger.com,1999:blog-1973750947775262558.post-77783259747034755082009-05-28T05:00:00.000-04:002009-05-28T05:52:32.212-04:00Continuous Integration with ColdFusion, Hudson, and MXUnit: Getting Started<p>This series will demonstrate how to set up a continuous integration (CI) environment for ColdFusion projects using <a href="https://hudson.dev.java.net/" target="_blank">Hudson</a> CI and MXUnit. We’ll cover Hudson setup, MXUnit test runs and JUnit XML output, and a few notification mechanisms (email, IM).</p> <h2>Installing Hudson</h2> <p>This will cover the super-duper simple way to run Hudson, which you'd do for testing this stuff out. DO NOT RUN YOUR REAL CONTINUOUS INTEGRATION ENVIRONMENT IN THIS MANNER. If you already have Tomcat set up, then you know how to install war files so follow that procedure instead (i.e. drop the war where you put your war files, or use the admin to deploy the war. It's that simple) </p> <ol> <li>Download the Hudson war file and put it somewhere </li> <li>Open a command line and navigate to the war file location </li> <li>type “java –jar hudson.war” </li> <li>This will launch Hudson. You can navigate to <a href="http://localhost:8080">http://localhost:8080</a> and from there, you’re ready to start </li> </ol> <p></p> <h2>Pulling your project from Subversion (SVN)</h2> <ol> <li>Click "create a new job" </li> <li>Give your job a name, and then select Freestyle Software Project </li> <li>Under Source Code Management, select SVN, and then plug in your project’s SVN location, eg <a href="http://svn.myproject/whatever/trunk">http://svn.myproject/whatever/trunk</a> </li> <li>From here, you can click “Save” and then perform a build by clicking “Build”. This will check out your code into the Hudson workspace for your project </li> </ol> <p><b>But this code isn’t where I need the code to be!</b> Good point. As I get started with this, I’m going to just keep doing it this way until I figure out a better approach. At least where I work, we have DEV servers where code is automatically updated from SVN anyways, and our unit tests all run against the DEV server. I’m not setting up a CI environment in order to set up yet another server; instead, I’m setting it up so that I can get better reporting and notifications while still executing the same tests against the same code.</p> <div class="note">Hudson does allow you to choose a “custom workspace”, but I’m not going to get into that right here as I’m not sure yet whether it’s relevant for ColdFusion projects. I can see people being tempted to set the Hudson workspace to an existing project location on a Dev server, for example. Time will tell if this proves to be a good idea</div> <h2>What’s Next?</h2> <p>See how easy that was? Next up, configuring ANT, running your tests, and recording results</p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-7778325974703475508?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com1tag:blogger.com,1999:blog-1973750947775262558.post-32316293043667016102009-05-22T14:00:00.001-04:002009-05-22T14:06:58.269-04:00ColdFusion and LiveCycle ES: Rights Management<p>This is the final part of a planned <a href="http://blog.mxunit.org/search/label/LiveCycle">3-part series</a> on getting started with LiveCycle ES for ColdFusion developers. With this post, I aim to: </p> <ol> <li>walk through the steps for Configuring LiveCycle Rights Management </li> <li>show how to invoke the RightsManagementService webservice </li> <li>address some additional issues I hit which stakeholders should understand </li> </ol> <p>Big Caveat: I’m just learning this stuff. I have not worked with an Adobe salesman or tech support, so it’s highly probable that the stuff I’m talking about in configuration is complete crap. This post is a diary of what I went through to merely get it all working, and by “working”, I mean “I was able to create a rights-managed PDF that communicates with the LC server”.</p> <h2>Configuring LiveCycle</h2> <p>Make sure the service is enabled in LC Admin: Services, Applications and Services, Services Management, Filter on “Rights Management”, and ensure “RightsManagementService” is running. Click on that link and ensure the default soap endpoint is enabled.</p> <h3>Create a new group</h3> <p>I’m not sure if I needed to do this, but I did it, so I’m documenting it.</p> <ol> <li>Settings – User management – Users and Groups </li> <li>Click “New Group” button. Created group named “Rights Management” </li> <li>Clicked through and gave the group permissions associated with Rights Management stuff. You do this when you get to Step 4 and then click “Find Roles”, then select the stuff that looks rights-management-ish. Again… consult a professional, not me. </li> </ol> <h3>Create a new user</h3> <p>For the purposes of this post, I’m going to skip anything related to creating new domains. Instead, when we invoke the webservice, we’ll just invoke with the default domain that ships with LC. It goes without saying that when you do this in the real world, you’ll need to a) know your sh*t and b) probably consult with a company to help you get all this set up. Again, this is just to get up and running for a POC.</p> <p>Now, then:</p> <ol> <li>Settings – User Management – Users and Groups </li> <li>Click “New User”. Give this user a name, username, password, blah blah blah. For this POC, select “DefaultDom” as the domain. Click next </li> <li>Click “Find Groups”, and select the new Rights Management group that you created above </li> <li>At step 3, I ignored Find Roles and went to Finish. </li> </ol> <h3>Create a new Policy Set</h3> <ol> <li>Services – Live Cycle Rights Management ES – Policies -- Policy Sets. </li> <li>Click “New”. Give it a name. Click next </li> <li>Search for a domain. I selected “Default Domain”. Click through and accept the addition.</li> <li>Click Next, then search for the User you just created. Click Next and give that user permissions to monkey with policies in documents</li> <li>I added that user to Document Publishers, too. Click through to finish</li> </ol> <h3>Create a new Policy</h3> <ol> <li>Services – LiveCycle Rights Management ES – Policies</li> <li>Click the link for the Policy Set you just created</li> <li>Click the Policies tab, then click “New”</li> <li>Give your policy a name</li> <li>Apply whatever settings you want. Click Save</li> <li>Check its checkbox, then click the Enable Button. Click through to finish.</li> <li>In your webservice call, you’ll use the policy set name and the policy name, along with the user and domain you associated with the policy set</li> </ol> <h3>Grrrrrrr</h3> <p>If you do all the stuff I’ve just talked about, you might be thinking “Gee, the LC Administrator is a bit tough to get around”. I’d respond with “ya think, Beav?”. I have come to despise the administrator. I’m assuming that Adobe wants you to use Workbench for most of this stuff. That, to me, is the only possible explanation for creating an admin that is so user-unfriendly. It’s a navigational nightmare.</p> <h3>Configuring SSL</h3> <h4>Set the Rights Management Server URL</h4> <p>Services – LiveCycle RightsManagement ES – Configuration – Server Configuration</p> <p>Set the Base URL to an SSL URL. For my POC, I used <a href="https://localhost:8443/">https://localhost:8443</a></p> <h4>Enable SSL in JBoss</h4> <p>I followed Duane Nickull’s <a href="http://www.adobe.com/devnet/livecycle/articles/enabling_ssl_jboss3.2.5.html">excellent instructions</a>. A few gotchas though:</p> <p>First, in a “note” in the middle of the page, he writes: “<strong>Note:</strong> If you installed the Adobe LiveCycle 7.2 release using the turnkey installers, the path to this will be different. It should be: <br /><kbd>$JBOSS_HOME/server/all/deploy/jbossweb-tomcat50.sar”.</kbd> </p> <p>Pay attention to that note. Don’t gloss over it.</p> <p>Second, a very very important point that is not addressed (well… I believe it’s just plain wrong, at least as of this writing): when you create the keystore, you need to set the “first and last name” as the name of the server on which you intend to deploy this. For my POC, I used “localhost”. In fact, I used “localhost” for every damn answer. Note that this is just if you’re using a self-signed keystore; if you used a real one (i.e. you buy a cert), you won’t have to go through this rigamarole.</p> <p>Finally, Duane shows how to get the cert installed via FireFox. On my Vista machine, this didn’t work. I had to use Internet Explorer, and I had to follow the steps below.</p> <p><strong>Now, if you haven’t done so already, restart JBoss. </strong></p> <h4>Making your cert a “trusted” cert on your machine</h4> <ol> <li>In Internet Explorer, navigate to the URL you specified in the Server Config above. For example, I navigated to <a href="https://localhost:8443/">https://localhost:8443</a> </li> <li>It’ll give you a red error address bar, so you’ll need to install the certificate. Right click and hit “install” or whatever the options are. </li> <li>This will launch IE’s certificate install wizard. Start the process, and when you get to the certificate store page, do not accept the default. Instead, select “Place all certificates in the following store”, click “browse”, and select “Trusted Root Certificate Authorities”. </li> <li>Click through to the end and you should be all set up. </li> </ol> <p> </p> <p> </p> <h2>Invoking the RightsManagementService with ColdFusion</h2> <p></p> <pre class="cf" name="code"><br /><cfscript><br />creds = {username='administrator',password='password'};<br />serviceRoot = "http://localhost:8080/soap/services/RightsManagementService";<br />wsdl = "#serviceRoot#?wsdl";<br />ws = createObject("webservice",wsdl,creds);<br />ws._setProperty("javax.xml.rpc.service.endpoint.address","#serviceRoot#?blob=base64");<br /><br />filePath = expandPath("readme.pdf");<br />theFile = fileReadBinary(filePath);<br /><br />inPDFDoc = {contentType="application/pdf",binaryData=theFile};<br />documentName="readme.pdf";<br />policySetName="Marc Policy set";<br />policyName="loose2";<br /><br />response = ws.applyPolicy(inPDFDoc,documentName,policySetName,policyName,"cf","DefaultDom");<br /><br />outputData = toBinary(response.getBinaryData());<br /></cfscript><br /><br /><cfset newfile = expandPath("readme_withrights.pdf")><br /><cffile action="write" file="#newFile#" output="#outputData#"></pre><br /><br /><h2>Additional Issues and Considerations</h2>As of this writing, whenever I open a rights-managed PDF created using the above steps, the PDF still prompts me twice: Once telling me that the PDF has to connect to the LC server, and once asking me for a username/password. I am 99% certain this is a configuration problem on my end. I just haven’t dug enough to figure it out yet. If you know how, please let me know. When I get back to my LC proof of concept, I’ll get the answers and update this post.<br /><br /><p>I believe it’s important for stakeholders deciding whether Rights Management is right for them to get solid answers – with proof – regarding the user experience with RM-managed PDFs. In my specific case, the PDFs wouldn’t be for internal consumption; rather, they’d be sent out to the masses, whose technical savvy could range from “My grandmother” to “my boss”. Bottom line: know your users.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-3231629304366701610?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com0tag:blogger.com,1999:blog-1973750947775262558.post-35428744232263677952009-05-21T06:00:00.002-04:002009-05-21T07:06:45.999-04:00ColdFusion and LiveCycle ES: Reader Extensions<p>With this post, I aim to </p> <ol> <li>walk through the steps I took to get LiveCycle configured for applying Reader Extensions </li> <li>show how to invoke the ReaderExtensions webservice with ColdFusion </li> </ol> <p>With this post, I do not aim to show you how you’d actually use the ReaderExtensions in real life. I have no idea if “real” production applications would be invoking these services; It seems that “The LC Way” involves you creating new processes in LC Workbench and using watched folders and such. I do not know what benefits are conferred by that approach over the approach I’ll demonstrate below. Again, as I said in my <a href="http://blog.mxunit.org/2009/05/getting-started-with-livecycle-es-for.html">first post on this topic</a>, this series is my way of recording what I went through to get this stuff working as I build a proof-of-concept.</p> <h2>Configuring LiveCycle</h2> <p>Login to LC, and click “Services”. Then go to “Applications and Services”, then “Services Management”. In the resulting dropdown, select “Reader Extensions” and submit. Check off the “ReaderExtensionsService” checkbox, and hit the “start” button if it’s not started.</p> <p>Click on that link, and then select the checkbox beside “Default Soap Endpoint”. Click the “enable” button if it’s not enabled.</p> <p>Click on the Services tab, and from there you can control whether to require authentication (which you’ll pass in the “creds” struct below) and also how to run the service. I kept mine at “System”, but I imagine in real production you’d run it as something else. I’m no LC expert, so I have no valid opinions here. </p> <p> </p> <p> </p> <h2>Invoking the ReaderExtensions webservice with ColdFusion</h2> <p>Invoking the ReaderExtensionsService from ColdFusion is reasonably easy, once you get around a few gotchas. First, you will probably need to pass authentication credentials. To get started, I just used the credentials I use to log in to LC Admin. You can turn off the need for credentials by going into LC Admin, navigating to the ReaderExtensionsService config, and turning authentication off.</p> <p>According to <a href="http://livedocs.adobe.com/livecycle/es/sdkHelp/programmer/sdkHelp/wwhelp/wwhimpl/js/html/wwhelp.htm?href=invokingSOAP.27.1.html">the docs</a>, you can get your extended PDF back from the webservice in 4 formats: base64-encoded, mime, dime, and as binary via a URL. I’ll show you the base-64 and remote URL approaches.</p> <h3>Base64</h3> <pre class="cf" name="code"><cfscript><br />creds = {username='administrator',password='password'};<br />serviceRoot = "http://localhost:8080/soap/services/ReaderExtensionsService";<br />wsdl = "#serviceRoot#?wsdl";<br />ws = createObject("webservice",wsdl,creds);<br />ws._setProperty("javax.xml.rpc.service.endpoint.address","#serviceRoot#?blob=base64");<br /><br />filePath = expandPath("readme.pdf");<br />theFile = fileReadBinary(filePath);<br /><br />inPDFDoc = {contentType="application/pdf",binaryData=theFile};<br /><br />usageRights = {enabledComments=true,enabledCommentsOnline=true,<br /> enabledDigitalSignatures=true,enabledDynamicFormPages=true,enabledFormFillIn=true,<br /> enabledOnlineForms=true};<br />applyOptions = {message="",modeFinal=true,usageRights=usageRights};<br /><br />response = ws.applyUsageRights(inPDFDoc,"marc","njUvw9Lnftxxxx",applyOptions);<br /><br />outputData = toBinary(response.getBinaryData());<br /></cfscript><br /><cfdump var="#outputdata#"><br /><br /><cfset newfile = expandPath("readme_extended_withbinary.pdf")><br /><cffile action="write" file="#newFile#" output="#outputData#"><br /><br /></pre><br /><br /><h3>Notables<br /></h3><p>First, note the very important couple of lines for getting LC to return the data in base64 format. Possibly this trick is new to you. It was to me, too, before I needed to dig into CF webservices and find out how to change the endpoint address after setting the wsdl in the createObject call. If you wanted mime or dime return, you’d do blob=dime or blob=mime, respectively. You can also do blob=http and it’ll give you the same result as the way I’ll do it down below. This endpoint resetting really tripped me up at first. I kept trying to call response.getBinaryData(), and the binary was empty. So, this is for you google searchers: empty binary data.<br /></p><p>Second, note that in your call to applyUsageRights, you need to pass valid user credentials. That crazy username/password combo was what I got from LC when I downloaded the trial version.<br /></p><p>Finally, the webservice call returns a datatype named “Blob”. No, this isn’t like a database blob. Instead, it’s an object of Adobe’s devising (I presume) that contains several methods you can call. CFDUMP it to see what’s available to you. Anyway, when you specify blob=base64 in the endpoint address, you can get back the new reader-extended PDF by calling response.getBinaryData(), and then you write that to a new file. Not that it matters, but I really like the Blob return type. It’s a great way to get consistent webservice calls across the various LC services. Props, dudes.<br /></p><br /><h3>RemoteURL<br /></h3><pre class="cf" name="code"><br /><cfscript><br />creds = {username='administrator',password='password'};<br />ws = createObject("webservice","http://localhost:8080/soap/services/ReaderExtensionsService?wsdl",creds);<br /><br />filePath = expandPath("readme.pdf");<br />theFile = fileReadBinary(filePath);<br /><br />inPDFDoc = {contentType="application/pdf",binaryData=theFile};<br /><br />usageRights = {enabledComments=true,enabledCommentsOnline=true,<br /> enabledDigitalSignatures=true,enabledDynamicFormPages=true,enabledFormFillIn=true,<br /> enabledOnlineForms=true};<br />applyOptions = {message="",modeFinal=true,usageRights=usageRights};<br /><br />response = ws.applyUsageRights(inPDFDoc,"marc","njUvw9Lnftxxxx",applyOptions);<br /></cfscript><br /><br /><cfset newfile = expandPath("readme_extended_withRemoteURL.pdf")><br /><br /><cfhttp url="#response.getRemoteURL()#"><br /><cfdump var="#cfhttp#"><br /><br /><cffile action="write" file="#newFile#" output="#cfhttp.filecontent.toByteArray()#"></pre><br /><br /><h3>Notables<br /></h3><p>Note that I’m using normal old createObject with a wsdl path… no resetting the endpoint here. When you call the service by default you get the response via a remote URL, NOT binary. This means you need to do a cfhttp call to the response object’s getRemoteURL() method, and then you use cfhttp.filecontent.toByteArray() to write it to a new file.<br /></p><p>Finally, I’m using the inline struct notation in these examples, but if you’re on a previous version of CF you can convert this code to normal old structnew() and you’ll be fine. Nothing about these calls should be specific to a version of CF.</p><br /><h2>Credits<br /></h2><p>Props to <a href="http://blog.tagworldwide.com/?p=11">this blog post</a>, which was the first post I read on using ColdFusion and LC together. This saved me a lot of time getting started.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-3542874423226367795?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com0tag:blogger.com,1999:blog-1973750947775262558.post-16715979158860962002009-05-11T05:00:00.000-04:002009-05-11T05:00:01.198-04:00Getting started with LiveCycle ES for ColdFusion Developers<h2> </h2> <h2>What is LiveCycle and why am I doing this? </h2> <p></p> <p>From the <a href="http://www.adobe.com/products/livecycle/">website</a>: “Adobe LiveCycle® ES (Enterprise Suite) software is an integrated server solution that blends data capture, information assurance, document output, process management, and content services to help you create and deliver rich and engaging applications that reduce paperwork, accelerate decision-making, and help ensure regulatory compliance.”</p> <p></p> <p>If you have trouble wrapping your mind around what exactly it is that LC ES can do you for you, you’re not alone. It’s not that LC is a solution in search of a problem; rather, it’s that LC does <em>a lot of stuff!</em> At its heart, LC is an enterprise Java app that provides a suite of services around document and information management. </p> <p></p> <p>I, however, do not yet have my head around all of its awesome. For me, it’s about one thing: doing stuff to PDFs that I otherwise couldn’t do, namely 1) unlocking functionality that lives in the PDF but which can only be exercised with Acrobat and 2) programmatically applying security policies to those PDFs. My company produces PDFs for public consumption, and the people opening those PDFs will probably not have Acrobat… just Reader.</p> <p></p> <p>Specifically, what I’m interested in is enabling Reader to save PDFs with form data still in tact; enabling “add comment” functionality in Reader; enabling digital signatures; and adding a “kill switch” into PDFs so that if the data goes out of date or is shown to be incorrect, the next time a user opens the PDF, the PDF can “phone home”, get instructions that the PDF is no longer valid, and give the user instructions for how to get a new version of the PDF.  And I need to do all of this programmatically.</p> <p></p> <p>You can do all of this with LiveCycle; you can do all of it with web service calls (i.e. SOAP); and you can do it all with ColdFusion.</p> <p></p> <p>To be clear: you are not dropping some jar files into your ColdFusion install. You are setting up a full JEE server (JBoss, WebSphere, whatever version of LC you download), and you are writing ColdFusion code that will send PDFs to the LiveCycle server, ask LC to do stuff to the PDF, and get new bytes in return. Then, rather than distribute the “source” PDF, you’ll distribute the new “extended” PDF. </p> <p></p> Finally, this is not about LiveCycle Data Services (LCDS). That’s a part of LiveCycle ES, but it’s not the part I’m interested in for this short blog series. Lots of people have written (with copious examples) about using LCDS with CF. This series will be about using other parts of LC, namely Reader Extensions and Rights Management. <p></p> <h2>Installing LiveCycle ES </h2> <p>For me, the fastest way to get LiveCycle up and running on my machine was to download the "Turnkey" trial edition here: <a href="http://www.adobe.com/cfusion/tdrc/index.cfm?product=livecycle">http://www.adobe.com/cfusion/tdrc/index.cfm?product=livecycle</a></p> <p>I selected the JBoss option because I have no experience with WebLogic or WebSphere. </p> <p>I'd say leave yourself at least a couple of hours to have LiveCycle installed and operational. This isn't a 5-second Tomcat download and 10-second exe install. It's a massive application, so adjust your expectations. Don't start this when you have an hour to go before you leave work (well... start the download then, and then let it go while you're driving home)  It's a weighty download, at almost 3 gig. </p> <p>You'll notice that there's no 64 bit download. This bit me in the ass. I am running this on 64 bit Windows, running the latest 64 bit JDK. The docs tell you that this only works on JDK5. Now, I don't know about you, but I'm the kind of guy who says "yeah, right", and proceeds. Fortunately, the LiveCycle installer asks you for your JDK path, and when you give it a Java 1.6 path, it won't let you proceed. Good on you, LiveCycle. </p> <p>So, off I went to get a 1.5 JDK (<a href="http://java.sun.com/javase/downloads/index_jdk5.jsp)">http://java.sun.com/javase/downloads/index_jdk5.jsp)</a>. I downloaded the 64 bit JDK cuz that's how I roll. Installed it, changed the JAVA_HOME environment variable to point to it, and off I went with the installer. </p> <p>Remarkably, I hit no other problems during the install. It takes a very long time, mind you. At times it might *appear* to be hung. Let it ride. </p> <p>So, it finished installing, then said "Starting JBoss Service".  And at that point, FAIL. JBoss started, then shut down right away.  Now this is more like it! I expected more of this, honestly, so I was kind of pleasantly surprised.  Off I traipsed to the Windows Event Viewer, where I found this gem: "The LoadLibrary function failed for the following reason: LoadLibrary is not a valid Win32 application." </p> <p>Obviously, this is due to my 64 bit JDK. So I proceeded to futz about in the JBoss install directory, looking for a .config or .properties or .xml or .whatever file that appears to point to my jdk, thinking I can just go download the 32 bit JDK, install it, change the config file to point to that, and be done with it.  This was not to be.  I'm no rocket surgeon, but as near as I can tell, the JDK path is either a) set into a registry entry or b) stuck in the Windows service config somewhere. I doubt it's the latter though because even starting JBoss with the bat file produced the error. So my money's on the registry entry. Anyhoo, not being adventurous (this was later in the evening), and being generally lazy when it comes to this stuff, I just installed a 32 bit JDK and restarted the LiveCycle install.  A few "OK" button clicks and gin & tonics later, and I was up and running. </p> <p>It takes about 10-15 minutes for LiveCycle to become responsive once JBoss starts, so don't be surprised when "starting JBoss" or 'starting LiveCycle" takes a really long time. </p> <p>You hit the admin UI link that they tell you on the installer, and up it pops. You will be greeted with a login screen reminiscent of the ColdFusion administrator. You’ll log in, and the similarities will end there. Queue the spooky music… you have entered a new dimension of sight and sound….</p> <h2>Summary </h2> <p>1) download the JDK 32 bit version <br />2) set your java_home variable to point to that version <br />3) when you download the installer, you'll be given a "serial number". I imagine this is just a stock trial serial. At any rate, copy it into a text file because you will need it later. <br />4) You will be prompted for a "credential" at some point during all of this. This is important! Write it down. I chose "Marc" as my credential, and then it gives some gibberish password. You will need this. </p> <p></p> <p>Next up.... Invoking the ReaderExtensions web service.</p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-1671597915886096200?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com1tag:blogger.com,1999:blog-1973750947775262558.post-47130469608104722642009-05-05T08:06:00.003-04:002009-05-05T08:09:12.289-04:00Articles on TDD and ColdFusion on Adobe Developer ConnectionWe're happy to announce a 2-part series on TDD and ColdFusion is now on the Adobe Developer Connection.<br /><br />Part 1 is here: <a href="http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt1.html">http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt1.html</a><br /><br />Part 2 is here: <a href="http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt2.html">http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt2.html</a><br /><br />Enjoy!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-4713046960810472264?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com4tag:blogger.com,1999:blog-1973750947775262558.post-43313133540000099422009-05-04T05:30:00.001-04:002009-05-04T07:25:24.728-04:00Timesavers: GMail Keys<div class="note">This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive </div> <p></p> <p>I’ve been a GMail user for quite some time, but only recently have I started using the GMail Keys feature. What a bonehead! Keys rock.</p> <p></p> <h2>Why I love Keys</h2> <ul> <li>Read every single email without clicking the mouse </li> <li>Easily "mark" emails read/unread/archived. For example, I get a lot of digest emails. I do skim most of them, but some days, I don't have time, so I'll mark em and archive em for later </li> <li>Perform common searches (all unread items in inbox) with just a few keys </li> <li>See the Keys Help with a single key combination (shift-Q) </li> </ul> <p>Here's what that help looks like, by the way: </p> <p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/Sfg228Bx7OI/AAAAAAAAAG4/Butn6JE7014/s1600-h/gmailkeyshelp%5B3%5D.png"><img title="gmailkeyshelp" style="border-width: 0px; display: inline;" alt="gmailkeyshelp" src="http://lh5.ggpht.com/__j-6QTK4wT8/Sfg23G8YS0I/AAAAAAAAAG8/Xtt_FTiQwto/gmailkeyshelp_thumb%5B1%5D.png?imgmax=800" border="0" height="154" width="244" /></a></p> <h2>Frequently Used Keys</h2> <b>From a message list (like the Inbox)</b> <ul> <li>c to compose </li> <li>x to select messages. </li> <li>j to go to next message. key to go to previous message </li> <li>y to archive </li> <li>enter to go into a message </li> </ul> <b>From a message (i.e. you're reading an email) </b> <ul> <li>x to get back to your list </li> <li>if it’s a multi-message conversation, use n to go to the next message, and p to go to the previous message. hit enter to expand if it’s not expanded </li> </ul> <p>You can also do searching really easily. Hit “/” to focus on the search box, then type some common phrases like “is:unread in:inbox” to show all unread messages in the inbox. In the video below, you’ll see more of that.</p> <p>And finally, shift-? shows the help for Keys</p> <h2>See it in Action</h2> <p>This isn’t the greatest video, but I love the java posse and the content of this lightening talk is a solid intro to using GMail Keys. I give you… the Dick Wall’s introduction to Keys.</p> <object height="340" width="560"><param name="movie" value="http://www.youtube.com/v/Fu2CAcphVuY&hl=en&fs=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/Fu2CAcphVuY&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="340" width="560"></embed></object><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-4331313354000009942?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com3tag:blogger.com,1999:blog-1973750947775262558.post-18252011281115506012009-05-01T05:30:00.003-04:002009-05-01T05:30:00.225-04:00Timesavers: Firefox Goodies<div class="note">This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive </div> <p></p> <p>This Timesaver is a quickie for some of the ways I stay fast in Firefox. I’m purposely leaving out Firebug, Greasemonkey, and any other add-ons for now. This is just native Firefox stuff.</p> <h2>Keyboard Shortcuts</h2> <p></p> <ul> <li>Ctrl-T to open a new tab </li> <li>Ctrl-L to focus on the address bar. I probably use this more times during the day than any other shortcut </li> <li>Ctrl-Enter to prefix with www and suffix with .com. For example, I’ll ctrl-L to the address bar, type facebook, then ctrl-enter. This could be shortened even further by adding a bookmark for facebook and giving it a keyword, like “fb”. Then I’d just type “fb” in the address bar and off I’d go to waste more time. </li> <li>Ctrl-F to find. I am amazed at how many times I see developers use the mouse to pop up the find box in Firefox and IE. </li> <li>“/” to start finding text right away without hitting ctrl-F </li> <li>‘ to start finding links right away. That’s an apostrophe if you couldn’t make it out. This is fast because if you have an idea of the links you’re searching for, like “contact”, you can hit apostrophe, then start typing “cont…” and then when it focuses on the link, you hit “enter” </li> <li>Backspace to go Back. Shift Backspace to go forward </li> <li>Ctrl-page-down to go to the next tab. Ctrl-page-up to go backwards through the tabs </li> <li>Ctrl-+ to zoom in. I need this because so many of the young hipster bloggers these days think it’s cool to write in 5 pt verdana. Ctr- - to zoom out (that’s control minus). And Ctrl-0 to return everything to normal. </li> </ul> <p></p> <p>The full list of shortcuts is here: <a title="http://support.mozilla.com/en-US/kb/Keyboard+shortcuts" href="http://support.mozilla.com/en-US/kb/Keyboard+shortcuts">http://support.mozilla.com/en-US/kb/Keyboard+shortcuts</a></p> <p></p> <p></p> <h2>Substitutions in Bookmarks</h2> <p>You know how when you focus in the address bar, and you type “google cat pictures”, and it does a Google search on cat pictures? It’s doing that with substitutions. Or try this -- Add this bookmark: "http://dictionary.reference.com/browse/%s" and give that bookmark a keyword of "dict". Then, Ctrl-L to your location bar and type “dict pedantic”. It’ll do a Dictionary search for the word pedantic. All that’s happening is that there’s a link stored in a bookmark, and somewhere in the link is “%s”. And the bookmark has a keyword assigned to it. So when you type the keyword -- “dict” for example – it loads that bookmark. Then, it sees the %s and expects something to come after the “dict”. so whatever else comes after the keyword in the address bar, Firefox will substitute for the %s.</p> <p>Where I work, this is particularly useful for loading URLs with a well-known pattern whose identifiers only differ by some ID number. Let's say I have a bookmark for executing the "build PDF" function in one of our applications. We'll give it a bookmark of http://app.foo.com/index.cfm?fuseaction=build&id=%s. I'll give it a keyword of "build". Then, to execute it in the url, I would type "build 1041", and it'd replace %s with "1041".</p> <p>Think of all the URLs you visit that differ only by some word or ID or whatever... they're prime candidates for keyword substitution.</p> <h2>Something I'm missing</h2> <p>I wish Firefox had a shortcut for "Send Link...". I know, I know... this is being rather pedantic. After all, you can just hit alt-f-e and do it the normal old windows shortcut start-with-alt-and-follow-the-letters way. But that feels cheap. I wish I could assign keys, so that I could do Ctrl-M.</p> <p>What are some of your favorite built-in Firefox timesavers?</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-1825201128111550601?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com3tag:blogger.com,1999:blog-1973750947775262558.post-85524248050971208912009-04-29T05:52:00.001-04:002009-04-29T05:52:00.315-04:00Timesavers: CFEclipse Snippets<div class="note">This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive </div> <p>Of all CFEclipse's features, none save me as much time as "<strong>Snippets</strong>". Eclipse has a built-in snippets feature, but for my part, I think CFEclipse's implementation is superior. </p> <p>You create snippets in the Snip Tree view. You give it a name, a "start block", and optional "end block", and a "trigger". In addition, you can use "variables" to have the snippet inserter prompt you for stuff. More on that later. </p> <p></p> <p>First, here's what the dialog looks like for creating/editing a snippet: </p> <p><a href="http://lh4.ggpht.com/__j-6QTK4wT8/SeWuSlDsZZI/AAAAAAAAAGQ/FdVgy2B3onI/s1600-h/snippet_new%5B3%5D.jpg"><img title="snippet_new" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="244" alt="snippet_new" src="http://lh3.ggpht.com/__j-6QTK4wT8/SeWuTFZJXQI/AAAAAAAAAGU/6AMHjlx4_4g/snippet_new_thumb%5B1%5D.jpg?imgmax=800" width="202" border="0" /></a></p> <p></p> <h2>Trigger Text</h2> <p> <br />For me, its killer timesaver is trigger text. I don’t have to open up the snip tree view, navigate through a tree of snippets, and click to insert. Just type the trigger text and hit Ctrl-J. </p> <p></p> <p>For example, I have a snippet for creating a new CFFUNCTION. In a cfc, I simply type: function and then hit Ctrl-J. Here's what my snippet looks like: </p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SeWuTWPTh-I/AAAAAAAAAGY/jMDlCsOLS3g/s1600-h/snippets_function%5B3%5D.jpg"><img title="snippets_function" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="snippets_function" src="http://lh3.ggpht.com/__j-6QTK4wT8/SeWuTl3nk7I/AAAAAAAAAGc/WWrzGc_f0So/snippets_function_thumb%5B1%5D.jpg?imgmax=800" width="244" border="0" /></a> </p> <p></p> <p></p> <p>And here's the popup I get when I hit Ctrl-J </p> <p></p> <p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/SeWuUIWvlMI/AAAAAAAAAGg/J5ipF9wR3Ic/s1600-h/snippets_functionpopup%5B3%5D.jpg"><img title="snippets_functionpopup" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="154" alt="snippets_functionpopup" src="http://lh5.ggpht.com/__j-6QTK4wT8/SeWuUZvOYiI/AAAAAAAAAGk/WYZa8DuG2kA/snippets_functionpopup_thumb%5B1%5D.jpg?imgmax=800" width="244" border="0" /></a> </p> <p></p> <p>I assign triggers to all the snippets I use on a day to day basis. I do have a number of snippets I use rarely, but I keep them as snippets because I figure if I have to type it more than once, it’s worth being in a snippet. But since I rarely use them, I’d forget the snippet trigger anyway.</p> <p></p> If you were to chop out the trigger functionality tomorrow, I could measure my productivity loss in hours over the course of a year. And I’m not a fan of losing hours. <p></p> <h2>Variables </h2> <p>Variables are placeholders for text that you will be prompted to enter when you insert a snippet. For example, in that function snippet above, you saw this: </p> <p>cffunction name="$${Function Name}" output="false" access="$${Access:public|private|package|remote}" returntype="$${Return Type:any|void|string|numeric|struct|array|query}" hint="$${Hint}" </p> <p>And then when I inserted the snippet, it gave me a dialog where I'd populate those placeholders. If you don't enter anything, it just enters an empty string instead. Note also that you can create a dropdown list by using a pipe-delimited list, as in the "returntype" attribute above. Finally, if you use the same variable twice in a snippet, it will only prompt you for it once and then it will insert it in each place it was requested. </p> <p>CFEclipse comes with several useful built-in variables you can use, too. They can be found at the official documentation site: <a title="http://trac.cfeclipse.org/cfeclipse/wiki/CFSnippets" href="http://trac.cfeclipse.org/cfeclipse/wiki/CFSnippets">http://trac.cfeclipse.org/cfeclipse/wiki/CFSnippets</a></p> <p>You can watch Mark Drew’s video on using snippets here: <a title="http://cfeclipse.org/assets/movies/07_Snippetsfla.html" href="http://cfeclipse.org/assets/movies/07_Snippetsfla.html">http://cfeclipse.org/assets/movies/07_Snippetsfla.html</a></p> <p></p> <p>Finally, if you’re interested, <a href="http://mxunit.org/doc/zip/snippets.zip">here are some of the snippets I use every day</a>. Many of these were created by my former colleague and all around good egg, <a href="http://mrmx.blogspot.com">Mike Rankin</a>.</p> <p></p> <p><strong>Bottom line</strong>: Next time you find yourself typing code that you've typed more than once, stop. Add it as a snippet, assign it trigger text, and execute the snippet by typing your trigger text then hitting Ctrl-J</p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8552424805097120891?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com5tag:blogger.com,1999:blog-1973750947775262558.post-6601113570275942272009-04-27T05:25:00.001-04:002009-04-27T07:54:37.127-04:00Timesavers: CFEclipse Scribble Pad<div class="note"> This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive </div> <p>One of my favorite CFEclipse features is the "Scribble Pad". Its primary purpose is exactly what its name suggests: to jam out some quick, throwaway code. I use it all the time when I come across a new function I want to test, or I want to see how a chunk of code will behave in isolation before I drop it into real production code. </p> <p>The scribble pad is simply a .cfm file that you keep in a project somewhere. I'm a big fan of having at least one "Sandbox" project in my workspace, so that's where I keep my scribble pad file. Here's how I set up scribble pad: </p> <p></p> <ol> <li>Ctrl-N and create new CFML project named "Sandbox" </li> <li>Store project at c:\inetpub\wwwroot\sandbox </li> <li>Ctrl-N to create new file named "scribble.cfm" in that project </li> <li>Hit the scribble icon in the toolbar (it's the one that looks like a pencil). </li> <li>The first time you do this, it should prompt you for the location of your scribble file. Point to your scribble.cfm, and give it the appropriate URL. In my case, it's <a href="http://localhost/sandbox/scribble.cfm">http://localhost/sandbox/scribble.cfm</a> </li> </ol> <p></p> <p></p> <p>Then, when you have some code you want to try out, hit F8 or click the scribble icon. This will load your scribble file. It will also load the CFEclipse Browser View and run the scribble.cfm page. As you modify your code, hit F5 to refresh the Browser view and see your changes. You do not need to give the browser focus in order for F5 to refresh it; you can keep your cursor in the code. </p> <p></p> <p>Here’s what it looks like:</p> <p></p> <p></p> <a href="http://lh4.ggpht.com/__j-6QTK4wT8/SeWoChz0xvI/AAAAAAAAAFw/WzIa7cDWm50/s1600-h/scribble_load%5B1%5D.jpg"><img title="scribble_load" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="156" alt="scribble_load" src="http://lh5.ggpht.com/__j-6QTK4wT8/SeWoC0mkmII/AAAAAAAAAF0/WDi6o6z2-i4/scribble_load_thumb%5B1%5D.jpg?imgmax=800" width="244" border="0" /></a> <p></p> <p></p> <p>Then, as you monkey with the code, you simply hit refresh in the Browser view to see the changes. </p> <p></p> <p>Note: if you hit the scribble icon and nothing happens, you may need to set up the scribble in your preferences. </p> <p><em>Window -- Preferences -- filter on Scribble </em></p> <p></p> <p> <p>It'll pop up a box that looks like this: </p> <p> <p></p> <p></p> <p></p> <p><a href="http://lh4.ggpht.com/__j-6QTK4wT8/SfWc-sPIATI/AAAAAAAAAGw/-pbrK15-UDc/s1600-h/scribbleprefs%5B7%5D.png"><img title="scribbleprefs" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="197" alt="scribbleprefs" src="http://lh3.ggpht.com/__j-6QTK4wT8/SfWc_CiF-zI/AAAAAAAAAG0/scR1JSMlAys/scribbleprefs_thumb%5B3%5D.png?imgmax=800" width="244" border="0" /></a> </p> </p> </p> <p></p> <p></p> <p>Then, enter in the appropriate information. In my case, I entered "scribble.cfm" as the file, "sandbox" as the project, and <a href="http://localhost/sandbox/scribble.cfm">http://localhost/sandbox/scribble.cfm</a> as the URL. If you don't enter in the URL, then the browser view will NOT load with the scribble URL; rather, it'll load empty, and this isn't what you want. </p> <p>For me, scribble is a huge timesaver because it gives me a quick place to test stuff without having to a) run the code inside my app or b) create new files for running it in isolation. </p> <p><strong>Bottom line: </strong>Scribble pad rocks. <strong>F8 </strong>loads it.</p> <div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-660111357027594227?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com2tag:blogger.com,1999:blog-1973750947775262558.post-82953955832399640872009-04-24T05:30:00.002-04:002009-04-24T05:30:00.335-04:00Timesavers: Eclipse Quick Diff<div class="note">This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive </div> <p>Have you ever been editing your code, and sometime down the road -- maybe 5 minutes, maybe 2 hours, maybe after lunch -- you break something. It used to work, and now it doesn't. You're thinking,<strong> "what change, of all the beautiful edits I've made, broke my fortress of code?"</strong> Being an experienced Eclipse user, you smile and say to yourself, "I know, I'll compare to my local history!". Or maybe you decide to simply compare to the latest SVN Version. </p> <p>So off you go, right-clicking on the file, selecting "compare", and then choosing a comparison target. Often, this is a perfectly reasonable decision. Well done, good sir. </p> <p>There is, however, a <strong>quicker way to easily see the changes you've made to your code</strong> in an editing session, or even across sessions: <strong>Quick Diff</strong> </p> <p></p> <p>On the left side of your Eclipse editor is the "ruler" bar. It's the thing with the line numbers. And if you have Quick Diff enabled, it's also the thing with the pretty colors showing you what lines have been added, changed, and deleted. Here's what Quick Diff looks like when I change a line of code and then hover over the ruler bar color decorator: </p> <p><a href="http://lh6.ggpht.com/__j-6QTK4wT8/SeWpRsGKWaI/AAAAAAAAAEw/fmvCM1XrKoc/s1600-h/quickdiffpopup_1%5B3%5D.jpg"><img title="quickdiffpopup_1" style="border-width: 0px; display: inline;" alt="quickdiffpopup_1" src="http://lh5.ggpht.com/__j-6QTK4wT8/SeWpSFXjMFI/AAAAAAAAAE0/6akVs1j29oI/quickdiffpopup_1_thumb%5B1%5D.jpg?imgmax=800" border="0" width="244" height="156" /></a></p> <p></p> <p></p> <p>Notice there's an "F2 for focus" line at the bottom of the popup. Here's what it looks like when you do that: </p> <p><a href="http://lh5.ggpht.com/__j-6QTK4wT8/SeWpSSHuh0I/AAAAAAAAAE4/48YwLdzNf3s/s1600-h/quickdiff_highlighting%5B3%5D.jpg"><img title="quickdiff_highlighting" style="border-width: 0px; display: inline;" alt="quickdiff_highlighting" src="http://lh3.ggpht.com/__j-6QTK4wT8/SeWpStAHkOI/AAAAAAAAAE8/4u3AXl0ochQ/quickdiff_highlighting_thumb%5B1%5D.jpg?imgmax=800" border="0" width="244" height="156" /></a> </p> <p></p> <p>What's cool is that you can select this text from the popup. So if you see something in your Quick Diff that you think "OOOH! That's the code I monkeyed with. Let me grab that and drop it back in and see if that fixes my problem", you can simply copy it from the popup and off you go. </p> <p></p> <p>"Added" lines of code will merely result in a "+" for each added line in the popup; Changes will show the full lines that were changed (though they won't give you the nifty "Compare Editor", which is one of the compelling reasons for using the full-on "Compare With" stuff). Deleted lines will give you a small line in the ruler bar. For example, I deleted a function, hovered over the black line, and this is what I got: </p> <p><a href="http://lh3.ggpht.com/__j-6QTK4wT8/SeWpS4oa_OI/AAAAAAAAAFQ/H6il88YdZwE/s1600-h/quickdiff_deleted%5B3%5D.jpg"><img title="quickdiff_deleted" style="border-width: 0px; display: inline;" alt="quickdiff_deleted" src="http://lh3.ggpht.com/__j-6QTK4wT8/SeWpTMpNL4I/AAAAAAAAAFU/uUMmEs3vQfo/quickdiff_deleted_thumb%5B1%5D.jpg?imgmax=800" border="0" width="244" height="156" /></a> </p> <p></p> <p></p> <p>To enable Quick Diff, simply open the Eclipse preferences (ctrl-shift-L, ctrl-shift-L), filter on "Quick", select the "Quick Diff" label, and have at it. Here you can also choose the Reference Source and change colors. It looks like this: </p> <p></p> <a href="http://lh4.ggpht.com/__j-6QTK4wT8/SeWpTpscSVI/AAAAAAAAAFY/Qc0772wq9Ko/s1600-h/quickdiff_preferences%5B3%5D.jpg"><img title="quickdiff_preferences" style="border-width: 0px; display: inline;" alt="quickdiff_preferences" src="http://lh4.ggpht.com/__j-6QTK4wT8/SeWpT4MHzYI/AAAAAAAAAFc/h2GCa512ONM/quickdiff_preferences_thumb%5B1%5D.jpg?imgmax=800" border="0" width="244" height="156" /></a> <p></p> <p>I use "Pristine SVN Copy" as the source for projects connected to SVN, and "Version on Disk" for non-SVN projects. </p> <p><strong>Bottom line</strong>: Enable Quick Diff, then hover in the gutter for popups showing you what’s changed. <strong>F2 </strong>to focus so you can select code</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8295395583239964087?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com3tag:blogger.com,1999:blog-1973750947775262558.post-77613676809943585422009-04-22T06:00:00.001-04:002009-04-22T06:00:00.526-04:00Timesavers: Tabaholic<div class="note"><br />This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive<br /></div><br /><span style="font-weight: bold;font-size:130%;" >Eclipse Resource Navigation</span><br /><br />If you're like me, you probably have a lot of files open in Eclipse at any one time. You probably have done the following things at some time in your career:<br /><br /><ul><li>Moused over to an already open file whose tab is visible in your window</li><li>Clicked on the little double arrow and drilled down to an already open file that wasn't visible in your window</li><li>edited a file, saved it, opened another file to check something out, then wanted to go back to the place where you were last editing</li></ul><br />This TimeSaver is dedicated to showing how Eclipse makes these operations a snap. Of course, we're talking about the keyboard. As you work with Eclipse, you'll learn that its developers are highly fond of keyboard shortcuts. Hit <span style="font-weight: bold;">CTRL-Shift-L</span> to see the current active shortcuts, also known as "Bindings".<br /><br /><span style="font-weight: bold;font-size:130%;" >Getting to open files quickly</span><br /><br />First, put down the mouse. It's sucking time away from you and your precious code! Every time you find yourself grabbing the mouse to go to an already opened file, stop. Pinch yourself. Yank on the <a href="http://en.wikipedia.org/wiki/Cilice">cilice</a>. Whatever. But put the damn thing down.<br /><br />And hit:<br /><br /><span style="font-weight: bold;">Ctrl-E</span><br /><br />Go ahead, try it right now. We'll still be here. Go to Eclipse, open up a few files, and then hit <span style="font-weight: bold;">Ctrl-E</span>. Pretty, isn't it?<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__j-6QTK4wT8/Sd1IJnTnfyI/AAAAAAAAADE/P6MAXYZF80k/s1600-h/ctrl_e.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 202px;" src="http://1.bp.blogspot.com/__j-6QTK4wT8/Sd1IJnTnfyI/AAAAAAAAADE/P6MAXYZF80k/s320/ctrl_e.jpg" alt="" id="BLOGGER_PHOTO_ID_5322489664629079842" border="0" /></a><br /><br />Notice how, like so many popups in Eclipse, it has a little area at the top where you can type? It's a filter. You can use wildcards, too. My favorite way to use it is when I know what file I'm looking for, let's call it "SomeTest.cfc", I hit Ctrl-E, type "So" and it'll filter down to the file I'm looking for. Hit Enter, and bam, you're at the file.<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Back from whence you came</span><br /><br />In that third scenario up above, you edited a file, went somewhere else, and then wanted to go back where you were. Eclipse has a shortcut for that: <span style="font-weight: bold;">Ctrl-Q</span>.<br /><br />Go ahead, try it.<br /><br />Did it work? If you were editing a CFM or CFC file in CFEclipse, it probably didn't. That's OK. We're going to take care of that.<br /><br />CFEclipse overrides the Ctrl-Q binding with the "repeat last tag" action. I personally don't use that, so I want to get rid of it. Let's open up the Keys preference page.<br /><br />The sloooooow way: Window -- preferences -- filter on keys<br /><br />The fast way: Ctrl-Shift-L, Ctrl-Shift-L again. Go ahead, try it. It's going to pop up a window that looks like this.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__j-6QTK4wT8/Sd1IGRO1TzI/AAAAAAAAAC8/GRHt37UK_nw/s1600-h/ctrl_q_unbind.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 278px;" src="http://2.bp.blogspot.com/__j-6QTK4wT8/Sd1IGRO1TzI/AAAAAAAAAC8/GRHt37UK_nw/s320/ctrl_q_unbind.jpg" alt="" id="BLOGGER_PHOTO_ID_5322489607163825970" border="0" /></a><br /><br />Now, in the filter box, type Ctrl+Q. Note the "<span style="font-weight: bold;">+</span>".<br /><br />You should see two entries. Simply remove the binding for "Repeat last tag" by selecting it and then clicking the "Unbind Command" button, or if you like that, you can assign it to another keyboard shortcut.<br /><br />Now, edit some text, move to another file, then hit Ctrl-Q. Bam... back where you were. Nice, eh?<br /><br /><span style="font-weight: bold;">I need to get to line 500... of line 2529</span><br /><br />You know you've written some really long files in your day. Admit it. Sometimes, you actually have to maintain those works of modern art, and it's nice to be able to get quickly to where you need to go within that file. Usually this comes from a bug report with a tag context / stack trace attached to it.<br /><br />Simply hit <span style="font-weight: bold;">Ctrl-L</span>, then type in the line.<br /><br /><span style="font-weight: bold;">Tab-to-Tab</span><br /><br />Ever wanted to just toggle through your open tabs? Simple: <span style="font-weight: bold;">Ctrl-PgUp</span> to go leftward through your tabs, and <span style="font-weight: bold;">Ctrl-PgDown</span> to go rightwards<br /><br /><span style="font-weight: bold;">The Back Button, Eclipse Style</span><br /><br />I'll admit, this isn't one I use much, but maybe you'll get some mileage out of it. It's like your browser's Back button, but for Eclipse: <span style="font-weight: bold;">Alt-Left</span><br /><br />Go ahead, try it.<br /><br />Guess how you go "forward".... yup. <span style="font-weight: bold;">Alt-Right</span><br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Summary:</span></span><br /><br /><span style="font-weight: bold;">Ctrl-E</span> to navigate open files<br /><span style="font-weight: bold;">Ctrl-Q</span> to go back to your last edit location<br /><span style="font-weight: bold;">Ctrl-L</span> to go to a specific line<br /><span style="font-weight: bold;">Ctrl-PgUp</span> and <span style="font-weight: bold;">Ctrl-PgDown</span> to toggle through your tabs<br /><span style="font-weight: bold;">Alt-Left</span> and <span style="font-weight: bold;">Alt-Right</span> to go back and forth<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-7761367680994358542?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com3tag:blogger.com,1999:blog-1973750947775262558.post-88093352430611647332009-04-21T06:33:00.003-04:002009-04-27T14:52:42.747-04:00Driven By The Cold - TDD, MXUnit, and ColdFusion (Part 1)<div xmlns="http://www.w3.org/1999/xhtml">It was a great learning experience to work with such talented people to deliver <a href="http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt1.html">this collaborative writing project</a> - peer/technical reviews, editing, editing, and more editing. This made blogging look like post-it hacks! A big thanks to Adobe for providing the venue, support, and process to publish technical know-how and best practices. Building good tools is one thing; showing people how best to use them is another. It's becoming glaringly apparent to this developer that a software product's strength lies equally in its ability to educate as well as it's ability to solve real-world problems. Community involvement is critical, and organizations that foster this collaboration will have a positive impact on the community.<br /><br />Part 1 is available now with Part 2 coming very soon.<br /><a href="http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt1.html"><br />http://www.adobe.com/devnet/coldfusion/articles/testdriven_coldfusion_pt1.html</a><br /><br /><br />Test and be Happy!<br />the guys at mxunit.org<br /><br /><div class="zemanta-pixie"><img src="http://img.zemanta.com/pixy.gif?x-id=32a915b5-e841-8eb7-982b-633197c7e3cb" class="zemanta-pixie-img" /></div></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8809335243061164733?l=blog.mxunit.org'/></div>billyhttp://www.blogger.com/profile/06624894387927690246noreply@blogger.com2tag:blogger.com,1999:blog-1973750947775262558.post-31373071728639131732009-04-20T06:00:00.002-04:002009-04-20T06:00:00.287-04:00Timesavers: Ctrl-Shift-R<div class="note"><br />This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive<br /></div><br />What you think of as files, Eclipse thinks of as <span style="font-weight: bold;">resources</span>. Resources represent a file in the Navigator or Package Explorer view; they represent a file opened in an editor. Your workspace comprises all the resources in your workspace (and a whole lot more).<br /><br />This TimeSaver is dedicated to <span style="font-weight: bold;">finding resources in your workspace</span>.<br /><br /><span style="font-weight: bold;font-size:130%;" >How To Quickly Find Resources</span><br /><br />By now, you should know I'm a fan of the keyboard. Navigating through trees of files is dog slow. I don't mean 8-week-old-yappy-rat-terrier-puppy slow. I mean 25-year-old-coon-hound-eyes-are-crusted-over slow. Fortunately, Eclipse gives us the "Resource" finder. Lucky people learn about this beauty early on in their Eclipse usage; others go without for a long time, to their woe. They Twitter, "How did I not know about Ctrl-Shift-R?" or "w00t! Ctrl-Shift-R!" or "OH: the dumbass in the cube beside me just found Ctrl-Shift-R. Dumbass. Wonder when he'll learn to breath out his nose". Why is this? I think it's because of the "resource" vs. "file" nomenclature discussed above. Why, for example, would you think to:<br /><br /><span style="font-style: italic;">Navigator --> Open Resource</span><br /><br />and expect that to pop up the single greatest popup in the history of bits and bytes?<br /><br />You wouldn't. That's why it goes undiscovered for so long.<br /><br />Notice the keyboard shortcut for "Open Resource": <span style="font-weight: bold;">Ctrl-Shift-R</span>.<br /><br />Burn that into your brain. Ctrl-Shift-R. Ctrl-Shift-R. Ctrl-Shift-R. Stop drinking. Stop eating. Stop smoking stogies. Stop raising your children. Stop everything until you have absorbed Ctrl-Shift-R. It is the fastest way to get to files. It looks like this, and it is my friend:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__j-6QTK4wT8/Sd1FevKZJ1I/AAAAAAAAAC0/dBUiVTAg5PA/s1600-h/openresource.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 267px;" src="http://3.bp.blogspot.com/__j-6QTK4wT8/Sd1FevKZJ1I/AAAAAAAAAC0/dBUiVTAg5PA/s320/openresource.jpg" alt="" id="BLOGGER_PHOTO_ID_5322486728980244306" border="0" /></a><br /><br />Notice how it filters when you type stuff? Notice I used a * to do a wildcard filter? Also, notice that little black triangle on the right hand side? You can drop that down and filter your search on Working sets for added radness.<br /><br />Another neat feature: it lets you select multiple files and open them. Need to super fast find all your TestCases and open them (why? I dunno)? Ctrl-Shift-R, then *Test.cfc. Tab into the "Matching Items Window, hit Ctrl-A, then Enter. Bam... you've got more open files than you know what to do with.<br /><br />Next time you find yourself grabbing the mouse and navigating through your tree of files, Stop. Put the mouse down. Even if you've found it already. Put the mouse down, hit Ctrl-Shift-R, and start typing.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-3137307172863913173?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com4tag:blogger.com,1999:blog-1973750947775262558.post-83592935881403618822009-04-17T06:00:00.003-04:002009-04-17T09:41:09.447-04:00Timesavers: Common Eclipse Shortcuts<div class="note"><br />This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive<br /></div><br />This TimeSaver is dedicated to common keyboard shortcuts that everyone should know. Well, let me back off of that. If you like being slower than a 3-toed Sloth, that's your prerogative. If you want to be fast, put the mouse down and use these shortcuts.<br /><br /><span style="font-weight: bold;">Ctrl-S</span> to Save<br /><span style="font-weight: bold;">Ctrl-Shift-S</span> to Save All<br /><br /><span style="font-weight: bold;">Ctrl-W</span> to close the current document<br /><span style="font-weight: bold;">Ctrl-Shift-W</span> to close all current documents<br /><br /><span style="font-weight: bold;">Ctrl-N</span> to pop up the "New..." dialog. Please, when you're creating new files, don't use the mouse. In your navigator or package explorer, put your mouse where you want your new file, and hit "Ctrl-N", then filter on the type of file or project or whatever you want to create, and hit Enter.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__j-6QTK4wT8/Sd1E45yoX2I/AAAAAAAAACs/zcy_-LAJAN0/s1600-h/newwizard.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 192px;" src="http://3.bp.blogspot.com/__j-6QTK4wT8/Sd1E45yoX2I/AAAAAAAAACs/zcy_-LAJAN0/s200/newwizard.jpg" alt="" id="BLOGGER_PHOTO_ID_5322486078998339426" border="0" /></a><br /><br /><span style="font-weight: bold;">Ctrl-M</span> to maximize (and minimize) the current active window. This works for editors and views.<br /><br /><span style="font-weight: bold;">Ctrl-F</span> to find stuff within your active editor<br /><span style="font-weight: bold;">Ctrl-K </span>and <span style="font-weight: bold;">Ctrl-Shift-K</span> to do "find next". I love these things! You highlight a word in your file, then hit ctrl-k to find other instances of it, one at a time. Go ahead, try it. use Ctrl-Shift-K to find backwards<br /><br /><span style="font-weight: bold;">Ctrl-H</span> to find stuff in other files in your workspace.<br /><br /><span style="font-weight: bold;">Ctrl-Space</span> to pop up content assist (aka tag/function insight). This one bears some elaboration for us CFMLers. You know how when you type a function name, say reFind(, and it pops up the content assist? but then when it disappears you don't know how to get it back up again? Just hit Ctrl-Space. Go ahead, try it. Go find a function in your code, put your cursor after the paren, and hit Ctrl-Space. For the energetic, <a href="http://blog.mxunit.org/2008/10/one-said-getter.html">read my long diatribe</a> with a mini-section on what I call "Ctrl-Space-Learn".<br /><br /><span style="font-weight: bold;">Alt-Up</span> and <span style="font-weight: bold;">Alt-Down</span> to move a whole "selection" (a line, or a chunk of lines) up or down<br /><br /><span style="font-weight: bold;">Tab</span> to indent, <span style="font-weight: bold;">Shift-Tab</span> to de-indent<br /><br /><span style="font-weight: bold;">Ctrl-Shift-L</span> to pop up a box showing other keyboard shortcuts<br /><br /><span style="font-weight: bold;font-size:130%;" ><br />How do you get the swing of these?</span><br /><br />I started by keeping a printout on my desk. It was a start. But the real key for me was to try to develop a palpable aversion to the mouse. For example, if I found myself mousing to create a new file, even if I were almost finished. I'd cancel it and do it with the keyboard. I'd do the same thing for all the other operations above.<br /><br />I try to nurture good developer habits; becoming keyboard-addicted is one worth developing yourself.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8359293588140361882?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com10tag:blogger.com,1999:blog-1973750947775262558.post-5561525389006781262009-04-15T05:30:00.004-04:002009-04-15T07:23:13.457-04:00Timesavers: Launchy<div class="note"><br />This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive<br /></div><br /><p><a href="http://launchy.net/" rel="nofollow">Launchy</a> is in my top 5 favorite applications, ever. Simply put, it makes it braindead simple to "do stuff" with just the keyboard. Some of the things I use it for:</p> <ul><li>Running bat files</li><li>Opening applications (Eclipse, Fireworks, TweetDeck, etc)</li><li>Opening/executing RDP shortcuts</li><li>Quickly navigating to directories</li></ul> <p>To use launchy, you simply hit "alt space", and the launchy window pops up. You start typing, and it looks in its cache for stuff that matches what you're typing. When you find something, you hit "enter". Your "thing" launches. That's it.</p> <p>Here's what it looks like:</p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/Sdn5T_QdZxI/AAAAAAAAACU/em6JEbFNmBc/s1600-h/launchy.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 191px;" src="http://4.bp.blogspot.com/__j-6QTK4wT8/Sdn5T_QdZxI/AAAAAAAAACU/em6JEbFNmBc/s320/launchy.JPG" alt="" id="BLOGGER_PHOTO_ID_5321558556508251922" border="0" /></a></p><p> </p> <p>Once installed, Launchy by default will scan everything in your "All Programs" in the Start Menu. However, it's highly configurable, and this is where it shines.</p> <p><b>To register anything with Launchy:</b></p> <ol><li>pop up Launchy with "alt space"</li><li>click the "gear" icon in the top right</li><li>click the "catalog" tab</li><li>In the "Directories" box, you can use the "+" and "-" buttons to add directories. Once a directory is selected, you can add the File Types in that directory to add to the catalog. I commonly use .bat, .lnk (those are windows shortcuts), .rdp, and .exe<br /></li><li>Then you click "Rescan Catalog" and you're set! (you can set it to auto-scan the catalog every X minutes. Play around in the "General" tab to find out how)</li></ol> <p><b>Example</b></p> <p>Remember the "<a href="http://blog.mxunit.org/2009/04/timesavers-batch-files.html">Bat File Timesaver</a>" post? At the end, I said that there was a better way to launch bat files. You can launch them with no mouse clicks at all by simply registering them with Launchy! For example, in the screenshot above, I started typing "ecl" to launch eclipse. But I don't launch eclipse with its executable; instead, I launch it with a bat file that contains certain settings:</p><p><br /></p> <p><em>runEclipse.bat</em></p><p><em><br /></em></p> <p> c:\eclipse_34_rcp\eclipse.exe -showlocation -vm "C:\Program Files\Java\jdk1.6.0_12\bin\javaw.exe" -vmargs -Xmx512M -XX:MaxPermSize=256m -XX:+AggressiveOpts -XX:+UseParallelOldGC -XX:ParallelGCThreads=2 -XX:ThreadPriorityPolicy=1 -Xverify:none</p><p><br /></p> <p>This file lives with all my other bat files in a directory somewhere on my file system. So to register this and the others with Launchy, I just add that bat file directory in the "Catalog" tab, add the .bat file type, and hit Rescan. Done! Now, when I want to launchy eclipse, I simply hit "alt space" and start typing "eclipse" and up it will pop.</p><p>Here's what the config looks like:</p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/Sdn5bzzpKiI/AAAAAAAAACc/rpVVsZ-5IgE/s1600-h/launchyconfig.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 287px;" src="http://4.bp.blogspot.com/__j-6QTK4wT8/Sdn5bzzpKiI/AAAAAAAAACc/rpVVsZ-5IgE/s320/launchyconfig.JPG" alt="" id="BLOGGER_PHOTO_ID_5321558690873551394" border="0" /></a></p> <p><b>Easy access to directories</b></p> <p>If you find yourself accessing certain directories over and over again, you may have created a shortcut to that directory. Then you point and double-click to open it. You can shorten this even further by adding directories into Launchy. For example, I poke around in the mxunit and mxunit-cfmeetups directories all the time. Rather than point and click to them, I use launchy. For example, if I want to get into the "plugindemotests" directory inside of mxunit, I hit "alt space" to pop up Launchy, then start typing "plu" and it'll autofill that directory. I hit enter, and it opens in Windows Explorer. So far, I've added a lot of common directories and I've seen no slowdown in launchy's ability to find just what I'm looking for.</p><p>To configure launchy for directories, just add a directory into the "Directories" box, and on the left hand side, don't add any file types. Instead, check the "Include Directories" checkbox.</p><p>Here's what launchy looks like after adding a Directory:</p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__j-6QTK4wT8/Sdn6QM3nNFI/AAAAAAAAACk/tJZCQPt1ZCE/s1600-h/launchydirectories.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 151px;" src="http://3.bp.blogspot.com/__j-6QTK4wT8/Sdn6QM3nNFI/AAAAAAAAACk/tJZCQPt1ZCE/s320/launchydirectories.JPG" alt="" id="BLOGGER_PHOTO_ID_5321559590954284114" border="0" /></a></p> <span style="font-weight: bold;">Alt Space, baby! </span><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-556152538900678126?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com5tag:blogger.com,1999:blog-1973750947775262558.post-40177868292700703122009-04-13T06:00:00.007-04:002009-04-13T09:35:55.097-04:00Timesavers: Batch Files<div class="note"><br />This is part of an ongoing series on <a href="http://blog.mxunit.org/search/label/timesavers">Timesavers</a>. The goal is simple: short, easily-digestible posts designed to help developers get faster and more productive<br /></div><br /><p>A batch file on Windows is a .bat file that contains one or more commands. You can execute .bat files by double-clicking, via the command prompt, or even as an "executable" in a scheduled task. Their power as a timesaver is in their ability to encapsulate common functionality so that you don't have to click a lot or remember a lot. <b>This is predicated on the idea that every mouse movement/click is itself a time waster</b>.</p> <p><b>Common Example</b><br />How do you start/stop/cycle ColdFusion? Certainly one way to do it is through the Windows Services panel. Let's count the mouse movements:</p> <ol><li>Start Menu</li><li>Control Panel</li><li>Administrative Tools</li><li>Services</li><li>Scroll to Macromedia JRun CFusion Server</li><li>Click the "Stop" or "Start" button up top</li></ol> <p>And that's just for one action. Multiply that by the other services you frequently cycle. SQLServer? MySQL?<br /></p><p><br /></p><p><b>Bat Files for Scenario Above</b></p><p><i>CF_Stop.bat</i></p><p>NET STOP "Macromedia JRun CFusion Server"<br />NET STOP "Macromedia JRun Admin Server" </p><p><i>CF_Start.bat </i></p><p>NET START "Macromedia JRun CFusion Server"<br />NET START "Macromedia JRun Admin Server"</p><p><i>CF_Cycle.bat</i></p><p>NET STOP "Macromedia JRun Admin Server"</p><p>NET STOP "Macromedia JRun CFusion Server"</p><p>NET START "Macromedia JRun Admin Server"<br />NET START "Macromedia JRun CFusion Server"</p><p><br /></p><p><b>Where to store them?</b><br />Obviously, you don't want to go putting dozens of bat files on your desktop. So where to put them? I keep mine in a directory, and then add a shortcut to that directory into my windows taskbar by following these steps:</p> <ol><li>Right click in taskbar</li><li>select "Toolbars" </li><li>select "New Toolbar"</li><li>Navigate to the directory where your bat files live. Click "OK" through to the end.</li></ol> <p>From there, you can access your bat files from that new toolbar right from your windows taskbar. The nice thing about this approach is that you don't need to double-click on the file... just single click. Here's a screenshot of what it might look like:</p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/SeMozWmxlQI/AAAAAAAAADM/ZdEEwM_-MdY/s1600-h/batdir.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 268px; height: 298px;" src="http://4.bp.blogspot.com/__j-6QTK4wT8/SeMozWmxlQI/AAAAAAAAADM/ZdEEwM_-MdY/s320/batdir.JPG" alt="" id="BLOGGER_PHOTO_ID_5324144047188710658" border="0" /></a></p><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/Sdn0PQv34FI/AAAAAAAAACM/fUDksL74QX8/s1600-h/batfiles.jpg"><br /></a></p><p><b>Isn't there a better way?</b></p>Yup.... Stay tuned for the next Timesaver!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-4017786829270070312?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com6tag:blogger.com,1999:blog-1973750947775262558.post-80829388402805917122009-04-01T06:00:00.003-04:002009-04-01T06:00:00.609-04:00New MXUnit released: The Community EditionWe're pleased to announce <a href="http://mxunit.org/download.cfm">a new release of MXUnit</a>. This one's especially meaningful to us because it's largely contributions from the community. Big props to:<br /><br /><a href="http://www.barneyb.com/barneyblog/">Barney Boisvert</a> for contributing "run this method" links to the standard HTML test output. This has been in the EXT Grid view since its inception, but that feature never made its way back into the original runner. This is a particularly welcome addition because the standard test runner is much faster than the EXT view.<br /><br /><a href="http://jamiekrug.com/blog/">Jamie Krug</a> contributed a patch and tests for deficiencies in makePublic(). Our exchange <a href="http://code.google.com/p/mxunit/issues/detail?id=145">is here</a>. I gotta tell you, I wish open source worked like this all the time. Jamie posted a bug to the bug tracker -- a very well written bug, by the way -- included patches, went back and forth with me, wrote tests. Outstanding.<br /><br /><a href="http://coldshen.com/blog/">Denny Valliant</a> has been bugging us forever about making debug() available to all components, not just your tests. He got sick of waiting on me, so he did it himself. Thus, <a href="http://wiki.mxunit.org/display/default/Using+request.debug%28%29">request.debug()</a> was born. It rocks! This is one of those things that will cause some folk to throw up their hands and say "but you're violating [insert whatever it is we're violating] here". I agree. We are. Don't use it if it offends you.<br /><br /><a href="http://cfrant.blogspot.com/">Adam Haskell</a> contributed the first of several planned function attributes: <a href="http://wiki.mxunit.org/display/default/What+to+put+in+your+tests+%28Assertion+Patterns%29">mxunit:ExpectedException</a>. Bill, Adam, and I have been going on about this for a very long time (too long!) in preparation for MXUnit 2.0. Blah blah blah. Meanwhile, while we were yapping, Adam wrote the expectedException functionality (and Tests). It's such a time saver!<br /><br />In addition, you'll notice that the links above all point to the new MXUnit wiki. Thank Adam for all of that! We still have a lot of content to move over from the existing MXUnit docs. It'll get there (some day).<br /><br />We've also had a lot of great feedback and ideas contributed from community members. Thanks to Bim Paras, Tim Farrar, Bill Rawlinson, Bob Silverberg, and all the other smart people for the excellent dialogue!<br /><br />Finally, the eclipse snippets have been updated to reflect the expectedException attribute over the old try/fail/catch method for testing expected exceptions. If you like to code fast, please open up the instructions in the mxunit/cfeclipse/snippets directory. You'll be glad you did.<br /><br />Thanks everyone!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8082938840280591712?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com2tag:blogger.com,1999:blog-1973750947775262558.post-82948551211587259202009-03-27T06:56:00.004-04:002009-03-27T07:25:19.532-04:00How to piss off a developerThis is something I whipped up years ago to brighten up a coworker's sour mood. Enjoy!<br /><br /><br /><span style="font-weight: bold;">Want to piss off developers? </span>Aggravate them? Drive them toward crowbar-bashing road rage when driving home? Follow these steps for guaranteed asshole-ness:<br /><br />1. Field a call from the customer. Say YES to everything. Promise it in 5 minutes<br /><br />2. Run (do not walk) to the developer's desk. Huff and Puff and breathe like you just ran a marathon. If you have trouble affecting such respiratory dynamics, hold your breath for a minute and run in circles.<br /><br />3. Say something urgent like "This is urgent". Sweat is good. Tears are better.<br /><br />4. Explain your hands were tied and it's a production emergency and if the client doesn't get [insert thing they want here] right away we're going to lose all their business and we'll be closing up shop tomorrow. For added effect, say something like "Think of the children"<br /><br />5. DO NOT....LISTEN UP...THIS IS IMPORTANT.... DO NOT give the developer any documentation, specification, guidance, or explanation.<br /><br />6. Say "They want this [again, insert thing here] right now. Please get it to me. It's urgent" (repetition is key, as you may be sensing)<br /><br /> <blockquote>1. Super-Duper Ladder-Climber Tip: when you get sufficiently good (or are certified by a professional certifying agent), you can just forward emails from clients directly to developer without any additional need for commentary. Certificates generally confer upon the sender some degree of telepathic skill. Little known fact!<br /><br /> 2. All 9th graders learn that a 1 must have a 2. Here's my 2.</blockquote><br /> <br />7. Then, start to whisper to the developer so no managers hear the conversation. God forbid they know what you're working on<br /><br />8. Thank them profusely, effusively, gushingly, for the work they're about to do.<br /><br />9. Return to seat. Surf internet. Play some games. But do set your timer.<br /><br />10. In 3 minutes, email the developer. Use this template: "Dear [insert lackey's name here], Thanks so much again for getting this done on such short notice. It really means a lot to me, and to the client, that we continue to provide such world class service. You're a gem!"<br /><br />11. In 6 minutes, email the developer. use this template: "Dear [insert lackey's name here], Can you give me a report on your status? YOU'RE THE BEST!!!!". The timing of your use of ALL CAPS is a finely honed skill. Guidelines are thus:<br /><br /> <div style="margin-left: 20px;">1. IN GENERAL, USE THEM WHENEVER POSSIBLE. THERE IS NO MORE FORCEFUL MEANS OF PUNCTUATING YOUR POINTS THAN WITH CAPITAL LETTERS.<br /><br /> 2. EXCEPT WITH EXCLAMATION POINTS!!!!!!!!!!!!!!!!!!!!!!!!!!<br /><br /> 3. As the time between the initial client request and the current time increases (now() - InitialClientRequest --> Infinity), so too should the percentage of CAPITAL letters to lowercase ones.<br /><br /> 4. Post-issue communications, however, should use lowercase except in cases where use of lowercase violates standard written English. Like so:<br /> <div style="margin-left: 20px;"><br /> 1. Initial issue letter: I CANNOT STRESS ENOUGH THE IMPACT THAT NOT MEETING THIS DEADLINE WILL HAVE ON OUR FUTURE RELATIONS WITH THIS CLIENT<br /><br /> 2. Post-issue followup letter: "Received rpt. Pls forward to [insert list of people that you are too busy to forward this to yourself here]. tks." (See below for proper use of tks).<br /> </div><br /> </div><br />12. Repeat that step every 5 minutes. Each time, add another upper level manager to the CC list. In addition, BCC your colleagues so they can see how hard you're working and how slow the developer is and how it's so hard to deal with people who just don't get things done. This facilitates post-issue commiseration and is a critical team-building tool. Do not discount the importance of this step.<br /><br />13. Upon completion of task, forward report to client. Bask in your glory<br /><br />14. Email all management explaining what a good job the team did. Pepper with phrases like "here's another example of how our team provides world class service". Be liberal in your use of phrases such as "team" and "we". Third-person plural is GOLD. If it's good enough for the Queen of England, it's good enough for you.<br /><br />15. DO NOT DOCUMENT THIS. It's imperative that this go down the memory hole so that next time it comes up, the entire process can be started from scratch. Bug trackers are the devil's playground: avoid them.<br /><br />16. In 2 weeks, when client finally reads said report and complains that the headings are in the wrong font, send email to developer requesting a new report. use this template: "Dear [lackey], Remember that one report? The font was wrong. Please fix. This is urgent. Tks." Click the little red exclamation point in outlook. CC management. BCC colleagues. Also BCC your friends so they can see how tough you are. Make 50 printouts and leave at printer for all to see.<br /> <div style="margin-left: 20px;"><br /> 1. Note use of 'tks' in template<br /><br /> 2. This is a crucial communication technique. Your abbreviation is a cue that any socially adept recipient will immediately recognize as a manifestation of your disapproval of their performance. Most will respond by working harder. All people crave unabbreviation. It's human nature.<br /><br /> 3. If you feel you're dealing with a less emotionally intelligent recipient, start removing subjects from your sentences. This will serve to punctuate said disapproval. To wit: NOT "The font was wrong" but "Font was wrong". better yet: "Font wrong. Will follow up. Urgent. Tks."<br /> <div style="margin-left: 20px;"><br /> 1. Super-Duper Ladder-Climber Tip: do not perform this subject-cide when communicating with those whose position you wish to assume someday...only lackeys and those too inferior to be graced by your pronouns. Conserve your verbiage for those who matter.<br /> </div><br /> </div><br />17. One final basking. Hooooold it..... Hoooooold it...... Wait for it........... Ah, yeah. That was good.<br /><br />Good job<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-8294855121158725920?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com5tag:blogger.com,1999:blog-1973750947775262558.post-31454993722380471342009-03-24T05:34:00.021-04:002009-03-24T07:48:08.654-04:00Debugging WebService errors in ColdFusion<span style="font-weight: bold;font-size:130%;" >Overview</span><br /><p>This is an article about the process of debugging a strange error I received while trying to execute an external webservice using ColdFusion 8. The external service is a java service, using Axis2, running in WebSphere. But if you're just searching for an answer b/c maybe you've hit the same problem, scroll to the bottom. Otherwise, enjoy the show.<br /></p><br /><br />I was executing the service like so:<br /><br /><pre class="cf" name="code"><br /><cfset ws = createObject("webservice","http://XXXXX/webservices/services/WFIService?wsdl")><br /><cfset result = ws.initiateOrder(IlexCode="enr",OrderXML="<orders/>")><br /></pre><br /><p></p><span style="font-weight: bold;font-size:130%;" >It Started with this Error</span><br /><br />Here's the error:<br /><p><br />Cannot perform web service invocation initiateOrder.<br />The fault returned when invoking the web service operation is:<br /><br />AxisFault<br />faultCode: {http://www.w3.org/2003/05/soap-envelope}Server.userException<br />faultSubcode:<br />faultString: org.xml.sax.SAXParseException: Invalid encoding name "UTF-8; ACTION="URN:INITIATEORDERRESPONSE"".<br />faultActor:<br />faultNode:<br />faultDetail:<br />{http://xml.apache.org/axis/}stackTrace:org.xml.sax.SAXParseException: Invalid encoding name "UTF-8; ACTION="URN:INITIATEORDERRESPONSE"".<br />at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)<br /><br /><br />(for the lone bleary-eyed googler trying desperately to solve the same problem, i give you these keywords:<br />faultString: org.xml.sax.SAXParseException: Invalid encoding name "UTF-8; ACTION="<br />)<br /></p><br />Here's what it looked like so you can bask in its awesomeness:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/Sci_YRpUO6I/AAAAAAAAABk/nCOzi8Fi1ss/s1600-h/initialerror.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 129px;" src="http://4.bp.blogspot.com/__j-6QTK4wT8/Sci_YRpUO6I/AAAAAAAAABk/nCOzi8Fi1ss/s320/initialerror.png" alt="" id="BLOGGER_PHOTO_ID_5316709783885331362" border="0" /></a><br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Running the service from outside ColdFusion</span><br /><p>First, I wanted to be sure that the problem wasn't with the service itself, so I needed to execute it outside of ColdFusion. For me, the simplest way to do this is with the "Web Services Explorer" that comes with Eclipse WST (Google it, it's handy). So I fired that up, saw there were 3 different "Bindings", and I hit the first SOAP one (the Soap11 porttype) just fine.<br /></p><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/__j-6QTK4wT8/Sci_zn3DwYI/AAAAAAAAABs/dEIigaLvL2M/s1600-h/webservicesexplorer.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 194px;" src="http://4.bp.blogspot.com/__j-6QTK4wT8/Sci_zn3DwYI/AAAAAAAAABs/dEIigaLvL2M/s320/webservicesexplorer.png" alt="" id="BLOGGER_PHOTO_ID_5316710253705019778" border="0" /></a>The SOAP12 binding was unsupported, so I ignored it. I also ignored the HTTP Post binding. So in my head, what I'm thinking is "I can hit the service successfully from outside of CF. Now I'm in black box hell."<br /></p><br /><span style="font-weight: bold;font-size:130%;" >Trying to view the SOAP messages with TCPMon</span><br /><p>First, I needed to find out what differed between the SOAP being sent by the Web Services Explorer and the SOAP being sent by ColdFusion. Having done a fair amount of development with Apache Axis back in 2002/2003, and more recently while developing the MXUnit Eclipse plugin, I was familiar with using TCPMon for doing this kind of debugging. However, I never tried to use it for debugging remote services, only local ones. (And after spending a half hour or so with it yesterday, I <b>still</b> don't know how to use it for debugging remote services. If you know, please tell me!). Eventually, because all I was really interested in was seeing the SOAP envelope and the http headers being sent, I just copied the wsdl from the remote services, stuck it in an xml file on my computer, and pointed my webservice call in Scribble pad to the new URL: http://localhost:8124/playground/WFIService.xml?wsdl. I then fired up TCPMon and added a listener at Port 8124<br /></p><ol><li>from command line, navigate to C:\jrun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\lib</li><li>type java -cp axis.jar org.apache.axis.utils.tcpmon</li><li>The swing app pops up</li><li>Type 8124 into Listen Port (this is arbitrary!)</li><li>Target Port = 80 (though in my case, it doesn't matter anyway)</li><li>Click "add"</li></ol><p><br />I then executed my local version of the service like so:<br /></p><pre class="cf" name="code"><br /><cfset ws = createObject("webservice","http://localhost:8124/playground/WFIService.xml?wsdl")><br /><cfset result = ws.initiateOrder(IlexCode="enr",OrderXML="<orders/>")><br /></pre><br /><br />Again, This wouldn't actually "work work", but CF would at least try to send a soap request to this address, so I'd be able to see what was being sent to the remote server. Honestly, this didn't pan out. Based on the original error, I suspected the problem wasn't with the SOAP envelope but with the headers. If you'll remember from the original error message, it displayed: Invalid encoding name "UTF-8; ACTION="URN:INITIATEORDERRESPONSE"". I suspected the problem was with the Content-Type header being sent to the service, but when I looked at it in tcpmon, it showed up like so:<br /><br /><br />POST /webservices/services/WFIService HTTP/1.0<br />Content-Type: application/soap+xml; charset=UTF-8<br />Accept: application/soap+xml, application/dime, multipart/related, text/*<br />User-Agent: Axis/1.2.1<br /><br />And I had expected to see this in that header: "UTF-8; ACTION="URN:INITIATEORDERRESPONSE""<br /><br />For the screenshot lovers, it looked like this:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__j-6QTK4wT8/ScjAcpSy7oI/AAAAAAAAAB0/rpge3C86Fzo/s1600-h/tcpmon.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 204px;" src="http://3.bp.blogspot.com/__j-6QTK4wT8/ScjAcpSy7oI/AAAAAAAAAB0/rpge3C86Fzo/s320/tcpmon.png" alt="" id="BLOGGER_PHOTO_ID_5316710958464429698" border="0" /></a><br /><br /><br />So as of that moment, I was kind of perplexed. I'm sure folk with more experience consuming web services from a variety of external producers would know exactly what was going on. I, however, did not. Me + TCPMon = Fail.<br /><p></p><span style="font-weight: bold;font-size:130%;" ><br />Debugging with the Generated Java stubs</span><br /><p><br />Some time back I had read Nathan Mische's excellent article in FusionAuthority Quarterly Update on using complex datatypes in CF web services. In the article, he mentions something new in CF8: the ability to easily view the generated java stubs created by axis (this is how CF works under the hood: it uses the wsdl2java tool from axis to dynamically generate bindings based on the WSDL).<br /><br />I change my web service invocation like so:<br /></p><br /><pre class="cf" name="code"><br /><cfset args = {refreshWSDL=true,savejava=true}><br /><cfset ws = createObject("webservice","http://XXXXX/webservices/services/WFIService?wsdl",args)><br /><cfset result = ws.initiateOrder(IlexCode="enr",OrderXML="<orders/>")><br /></pre><br /><br />So I run the service again, get the error, and traipse on down to the stubs directory (in my case: C:\jrun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\stubs) and open up the most recent directory. Navigate on down, and there are the java files. I decided that I wanted to see if I could execute the service from outside of CF but using these source files, so I opened up my java playground project in Eclipse (you DO have at least one playground/sandbox/scratch project, right?!), added a new package, and dropped the source files in there. The screenshot below shows the eclipse directory where I copied the generated java files on the left; on the right is the stubs directory that ColdFusion creates. Note that it's a mix of java and class files. Normally, the java files aren't in there, but the "savejava=true" key in the arguments struct that I'm now passing to CF in the createobject() call ensures the java files stay there.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/__j-6QTK4wT8/ScjBCY56vbI/AAAAAAAAAB8/JHP1KqroGio/s1600-h/javasources.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 194px;" src="http://2.bp.blogspot.com/__j-6QTK4wT8/ScjBCY56vbI/AAAAAAAAAB8/JHP1KqroGio/s320/javasources.png" alt="" id="BLOGGER_PHOTO_ID_5316711606900145586" border="0" /></a><br /><br />When I first copied the files over into my new Eclipse package, I naturally got a bunch of errors. First, I needed to change the package declaration in the source files (alternately, I could've simply renamed my package). Second, I needed to add jar files to the the build path so that the source files would compile. This is simple:<br /><br />In Eclipse, in the project's "lib" directory, I created a new subfolder called "axis12". I did this b/c I didn't want to pollute my existing lib directory, and at the time I had suspected that maybe the problem was with CF using axis 1.2 and not 1.4 (I use 1.4 for the Eclipse plugin, so I had thought maybe I'd end up running these sources files under both axis 1.2 and 1.4 and therein would've lied the bug... turned out that's not what it was at all).<br /><br />Then, in C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\lib, I copied a whole bunch of jar files that looked like they'd be required. in the end, I copied all the ones you see highlighted in the "referenced libraries" from the screenshot below. I didn't need all of these to get the java to compile, but I did need them to get it to run without getting NoClassDefFound errors when actually running the code.<br /><br /><p><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/__j-6QTK4wT8/ScjFr5shaEI/AAAAAAAAACE/PufouAUcr78/s1600-h/requiredjars.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 194px;" src="http://3.bp.blogspot.com/__j-6QTK4wT8/ScjFr5shaEI/AAAAAAAAACE/PufouAUcr78/s320/requiredjars.png" alt="" id="BLOGGER_PHOTO_ID_5316716718123477058" border="0" /></a><br /></p>In addition, I created a new JUnit TestCase for executing the generated code (simply a start... no assertions, just something to run the code):<br /><p>WFIServiceTest.java:<br /><br />package marc.axis;<br /><br />...imports...<br /><br />public class WFIServiceTest extends TestCase {<br />public void testCompleteOrder() throws RemoteException, ServiceException, MalformedURLException {<br /> WFIServiceLocator locator = new WFIServiceLocator();<br /> System.out.println(locator.getWFIServiceSOAP11port_http().initiateOrder("enr", "<orders/>"));<br />}<br />}<br /><br /></p>After doing this stuff, the damn test case didn't error! Confound it all Samwise Gamgee! I had hoped against hope that by running the service using the stubs generated from CF that I'd hit the same error that I was hitting inside of CF. This way, I could at least step through it in the debugger and have a fighting chance of getting inside the black box to figure out how to fix this. Alas, this was not to be. It was time to take a break.<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >Distance</span><br /><br />Every programmer knows that one of the worst things you can do when faced with a hard-to-get-at problem of this type is to stare and obsess over it endlessly. You get tired. Your eyes hurt. Your brain turns to mush. Your shoulders ache. I really, really wanted to keep at this. Thankfully, in the background I hear my wife yell at my daughter, my daughter has a low-grade conniption (she's 5 and of late prone to such outbursts...), and Daddy has to swoop in and save the day. Being a dad always comes first. About an hour after the meltdown, it's tubby time. Afterward, I'm drying my daughter's hair, my brain's still working on the problem, and it hits me: it's the other bindings! Remember the ones from when I executed the service successfully in the Web Services Explorer (the Soap11 binding worked fine)? And remember how the Soap12 binding was unsupported, and I ignored the HTTP Post binding? Well.... they stuck in my head. And they had to be in the generated sources. So as I'm drying my daughter's hair, I'm thinking... what if CF is using one of those other bindings, and that's why I'm getting the error?<br /><br /><span style="font-weight: bold;font-size:130%;" >It's all about the PortName</span><br /><p><br />Now, at this point, I can think of nothing else. I HAVE to get downstairs and see if that's it. Problem is, I have a wet-headed kid. So I race through that, hand her off to my sweet wife (who's busy with our littlest daughter), and hit the computer again. I change this line in my test case like so:<br /><br />from System.out.println(locator.getWFIServiceSOAP11port_http().initiateOrder("enr", "<orders/>"));<br /><br />to<br /><br />System.out.println(locator.getWFIServiceSOAP12port_http().initiateOrder("enr", "<orders/>"));<br /><br /></p><span style="font-weight: bold;">Sweet, sweet stack trace:</span><br /><p><br />AxisFault<br />faultCode: {http://www.w3.org/2003/05/soap-envelope}Server.userException<br />faultSubcode:<br />faultString: org.xml.sax.SAXParseException: Invalid encoding name "UTF-8; ACTION="URN:INITIATEORDERRESPONSE"".<br />faultActor:<br />faultNode:<br />faultDetail:<br />{http://xml.apache.org/axis/}stackTrace:org.xml.sax.SAXParseException: Invalid encoding name "UTF-8; ACTION="URN:INITIATEORDERRESPONSE"".<br />at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)<br />at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source)<br />at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)<br />at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)<br />at org.apache.xerces.impl.XMLEntityManager.createReader(Unknown Source)<br />at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)<br />at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(Unknown Source)<br />at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)<br />at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)<br />.....<br /></p><br /><br /><p><br />That was it... CF was using the Soap12 binding instead of the Soap11 binding. So all I needed to do was get CF to use the correct binding, and my problem would be solved. How to do that? I remember reading in the docs that you could use the "portname" attribute to force CF to use a specific binding, so that's what I needed to do. Now... what's the portname to use? It's simple to discover what is available to you. Just look in the WSDL, scroll to the bottom, and find stuff that looks like this:<br /><br /></p><pre><br /><wsdl:service name="WFIService"><br /><wsdl:port name="WFIServiceSOAP11port_http" binding="ns0:WFIServiceSOAP11Binding"><br /><soap:address location="http://XXX/webservices/services/WFIService"/><br /></wsdl:port><br /><wsdl:port name="WFIServiceSOAP12port_http" binding="ns0:WFIServiceSOAP12Binding"><br /><soap12:address location="http://XXX/webservices/services/WFIService"/><br /></wsdl:port><br /><wsdl:port name="WFIServiceHttpport" binding="ns0:WFIServiceHttpBinding"><br /><http:address location="http://XXX/webservices/services/WFIService"/><br /></wsdl:port><br /></wsdl:service><br /></pre><br /><br />The names available to you for use in the portname attribute are the names in the wsdl:port elements. So I took the Soap11 portname, added it to the webservice invocation like so, and bam... problem solved:<br /><br /><pre class="cf" name="code"><br /><cfset ws = createObject("webservice","http://XXXXX/webservices/services/WFIService?wsdl","WFIServiceSOAP11port_http")><br /><cfset result = ws.initiateOrder(IlexCode="enr",OrderXML="<orders/>")><br /></pre><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">What I still don't understand</span><br /><br /></span>According to the CF Documentation, if you don't specify the portname, then CF will pick the first one it finds. Looking at the WSDL, the first element is the Soap11 binding. Why is CF using the Soap12 binding? I don't get it.<br /><br />There's another lesson here, aside from the fact that portname is scalded into my brain. It's a lesson about struggle. I believe that struggle is key to learning deep. You have to be willing to fight for your answers. Sure, I tried googling for the answer first! But when I didn't find it, I didn't stop there. You have to do the same thing. If you resort to the mailing lists or forums and paste in your 1000 lines of code, you're not just annoying the people who would otherwise try to help you; you're doing yourself a great disservice. Learning is hard; it takes time; it's even worse when you're under deadline pressure and you just gotta get this thing done. Still, if you want to grow, you gotta welcome the pain.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1973750947775262558-3145499372238047134?l=blog.mxunit.org'/></div>Marc Esherhttp://www.blogger.com/profile/05942611191966201181noreply@blogger.com1