Tuesday, July 01, 2008

ColdFusion Livedocs on AIR

I was doing a code review for Vinu today (dont ask me which feature it was :-)) and we needed to check the reference doc for a tag. And instead of opening the local doc page, he opened this cool application that had livedocs and it was blazing fast (I know Livedocs sucks ! and yes I work for Adobe ;-)).

I was like 'whoa!! thats a cool app.. Did you write it? Why dont you release it for public??' And then he told me that some one from the community had written it and its already available for everyone. It has been developed by Brian Love and it is available here. It has very small size application, very lightweight and extremely fast.

So in case you haven't downloaded it, download it now!! I am sure you would love it.

Monday, June 30, 2008

New 'EvalAtPrint' attribute in CFDocumentItem

A new evalAtPrint attribute has been added to cfdocumentitem tag in ColdFusion 801 which is applicable when the item type is header or footer. The default value of this attribute is false.

Note: The cfdocumentitem behavior with the default evalAtPrint value is identical to the behavior in ColdFusion MX 7, but differs from the behavior of the ColdFusion 8 release.

When the evalAtPrint attribute value is false, the default value, ColdFusion evaluates the cfdocumentitem tag body at the same time when it is processing the cfdocument tag. This is the behavior identical to CFMX7. In this case you can use CFDocument variables (TotalPageCount, CurrentPageNumber, TotalSectionpageCount and CurrentSectionpageNumber) only inside cfoutput and not in any expression because the page numbers are not known unless the cfdocument body content is evaluated and layed out.

In order to use CFDocument variables in expression inside CFDocumentItem tagbody, you should set evalAtPrint to true as shown in the following example.

<cfdocument format="pdf">
<cfdocumentitem type="header" evalAtPrint="true">
<cfif (CFDocument.currentPageNumber % 2 eq 0)>
<cfoutput> Page is even</cfoutput>
<cfelse>
<cfoutput> Page is odd</cfoutput>
</cfif>
</cfdocumentitem >
Document body…
</cfdocument>

In this case, ColdFusion evaluates the cfdocumentitem tag body when it prints the header or footer, not when it evaluates the cfdocument tag body. This ensures that the cfdocument tag body is already evaluated and layed out and page number information is available when cfdocumentitem tag is being evaluated

A side effect of this is, if a variable is used inside both cfdocument and cfdocumentitem, cfdocumentitem tag will only see the final value of that variable. In the following example, cfdocumentitem will always get 11 as value of ‘I’ and hence all the headers will print ‘Chapter 11’.


<cfdocument format="pdf" >
<cfloop from=1 to=10 index="i">
<cfdocumentsection>
<cfdocumentitem type="header" >
<cfoutput>Chapter #i#</cfoutput>
</cfdocumentitem >
DocumentSection body
</cfdocumentsection>
</cfloop>
</cfdocument>

To handle this, you can now pass the variable into the cfdocumentitem tag as a custom attribute, as shown in the following example:

<cfdocument format="pdf" >
<cfloop from=1 to=10 index="i">
<cfdocumentsection>
<cfdocumentitem type="header" evalAtPrint="true" no = #i#>
<cfoutput>Chapter #attributes.no#</cfoutput>

<cfif (CFDocument.currentPageNumber % 2 eq 0)>
<cfoutput> Page is even</cfoutput>
<cfelse>
<cfoutput> Page is odd</cfoutput>
</cfif>
</cfdocumentitem >
Document Body.
</cfdocumentsection>
</cfloop>
</cfdocument>

CFUnited Presentation - All about CFThread

I did a presentation on "All about CFThread" at CFUnited this year and I think it went fairly well. It was a repeat session - once on friday 21st June and another on Saturday 22nd June and both the sessions had pretty good number of people attending it. Thanks a lot to all those attended. As promised, I have uploaded my presentation and the sample code up here.

Please feel free to ask me questions if you have any.

Friday, June 27, 2008

Back from hiatus

I took a long long break from blogosphere and now that I am rejuvenated after CFUnited, I am back. :-) Thinking about it, it was a really long break - my last post was on Feb 18th which makes it 4 months. So what did I do in those last 4 months? Well lot of things ;-)

  • I GOT MARRIED :-) So thats the biggest thing that happened. I took a one month long vacation to get married, went to Mauritius for my honeymoon and we had a really great time. Here is one of our pics. In case you want to see more of these, you can head over to Flickr. :D

 

  • There was a more than one month long Cricket series called "Indian Premier League" and I watched each and every match ;-)
  • All of us in the ColdFusion team were quite busy (and still are) in research, planning and implentation for the Centaur. In other words, I was working for you guys.

Now that I am back, you should see some regular posts from me. The next one goes in a while.

Monday, February 18, 2008

Reading MP3 meta-data from ColdFusion

On friday I posted about how to read the meta-data for Swf (flash) file from ColdFusion and on the same note, I think it will be cool to read the meta-data for MP3 file as well. Here is the specification for MP3 header and it is fairly straight forward to read the header using the spec.

ColdFusion 8 knows how to read MP3 file and it can provide a set of meta-data for it. Though this functionality is not exposed via any tag or function, you can still use it. The meta-data it provides are

  • Bit Rate : in kbps
  • Frequency : in Hz
  • Play duration : in second
  • Version : integer
      • 0 - MPEG version 2.5
      • 1 - MPEG version 2
      • 3 - MPEG version 1
  • Copy Right : true/false
  • Channel mode : integer
      • 0 - Stereo
      • 1 - Joint Stereo
      • 2 - Dual Channel
      • 3 - Mono or Single Channel

Here is an example code.

<cfset mp3File = createObject("java", "coldfusion.util.MP3File").init("C:\music.mp3")>
<cfoutput>mp3File.getBitRate() : #mp3File.getBitRate()# kbps</cfoutput><br>
<cfoutput>mp3File.getFrequency() : #mp3File.getFrequency()# Hz</cfoutput><br>
<cfoutput>mp3File.getVersion() : #mp3File.getVersion()#</cfoutput><br>
<cfoutput>mp3File.getDuration() : #mp3File.getDuration()# Sec</cfoutput><br>
<cfoutput>mp3File.isCopyRighted() : #mp3File.isCopyRighted()#</cfoutput><br>
<cfoutput>mp3File.getChannelMode() : #mp3File.getChannelMode()#</cfoutput><br>

Though you can use the above mentioned class (coldfusion.util.MP3File) without any problem, you must keep it in mind that it is unsupported and *might* change in future. Just a disclaimer !!! :-)

This class does not get you the ID3V1 or ID3V2 meta-data, but it should be easy for you to do it. For ID3V1, all you need to do is to read the last 128 bytes of the mp3 file and you have all the information required. Reading ID3V2 tag is little more involved and there are a number of open source java libraries available (common one being jidlib and jaudiotagger) which can be used.

Friday, February 15, 2008

Reading Flash (Swf) metadata from ColdFusion

Wouldn't it be cool if you could read the meta-data of Swf file in ColdFusion? The most common use case I can think of is to find the dimension of swf movie so that you can set the dimension for the same in object tag while you are embedding the flash movie in your page. And the good news is that you can do that currently in ColdFusion with just 2-3 lines of code!! All you need to do is to create a TagDecoder and decoder the header with it. Here is the complete code.

<cfscript>
fis = createObject("java", "java.io.FileInputStream").init("C:\test.swf"); // Create the FileInputStream
decoder = createObject("java", "macromedia.swf.TagDecoder").init(fis); // create TagDecoder
header = decoder.decodeHeader(); // Decode the header.
fis.close();
rect = header.size;
WriteOutput("
Is Compressed : #header.compressed#<br>
Frame Count : #header.framecount#<br>
Frame rate : #header.rate#<br>
Version : #header.version#<br>
Height : #rect.getHeight()#<br>
Width : #rect.getWidth()#");
</cfscript>

The height and width value that you see here would be in twips which is defined as 1/20 of a point or 1/1440 inch. This means, for a 72 dpi screeen, you will have to divide it by 20 to get the height and width in pixels.

Monday, January 14, 2008

Adobe ColdFusion Survey

As promised earlier, here they come. As part of the research for Centaur (next major version of ColdFusion aka ColdFusion 9), we need your feedback on ColdFusion 8 features, what enhancements do you need in them, what new features you want in the new release etc etc.

Adobe ColdFusion Survey

We would also like your inputs on platform and vendor support for upcoming ColdFusion release.

Platform and Vendor Support

Please do take some time to take this survey as this would really help us shape the new features in the upcoming version. THIS is YOUR chance to get your favorite features in !

Thursday, January 10, 2008

DNS lookup Caching in ColdFusion/Java

Two days back, I got an interesting question from our support team. The Customer in this case was using CFLdap which connected to a particular LDAP server and things were working fine. The problem came when they replaced this LDAP server with another LDAP server and assigned the same dns name to the new ldap server. Ideally any connection made henceforth should have worked with the new ldap server but actually that did not happen. ColdFusion started throwing error and it did not work until the ColdFusion server is restarted. Ever seen something similar?

It is obvious that it happend because the IP address was being cached for the host name as a result of which ColdFusion was still trying to connect to the old IP address even though the host name now pointed to a different IP address. This caching also applies for all other network protocol tags such as CFHTTP, CFFTP, CFFEED etc and is not limited to CFLDAP. It is actually the JVM that does this caching. When JVM is requested to resolve a host name, it does the host name to IP address resolution and caches the result. This result will be used for all subsequent lookups. It also caches the negative results. By that I mean, if the dns reolution fails, it caches the failed result for a certain period so that any lookup for that hostname in that period will not result into another resolution on network and will immediately return the failed result.

For more detail on this caching, check out the Javadoc for InetAddress class.

As per this doc, there are two parameters that control this caching

networkaddress.cache.ttl (default: -1)
Indicates the caching policy for successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the successful lookup.

A value of -1 indicates "cache forever".

networkaddress.cache.negative.ttl (default: 10)
Indicates the caching policy for un-successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the failure for un-successful lookups.

A value of 0 indicates "never cache". A value of -1 indicates "cache forever".


Now where do you specify this settying? You can specify this setting in <Java_home>/jre/lib/security/java.security file. For standalone ColdFusion server it will be in <ColdFusion _dir>/runtime/jre/lib/security/java.security file.

As you see, by default networkaddress.cache.ttl caches the result for ever and hence it is configured for best performance. Any change to this mean drop in performance. If you don't want to cache the resolved IP address for ever, as is the case here, you would need to change networkaddress.cache.ttl value to 60 seconds or 300 seconds or any value you feel suitable. You would not want to set it to 0 as that would mean "never cache" the result which might affect the performance significantly.

In which case you would want to change the value for networkaddress.cache.negative.ttl? That would be mostly in case when you want to cache the negative result for a longer time and in turn improving the performance. For example, if you are trying to connect to a hostname which can not be resolved to any ip address, and that happens very frequently, each of the call (as long as they are not in the same 10 sec window) would become very slow. Increasing this value would increase the performance but again you would not want to cache the negative result for ever.

After you change this setting, you will have to restart the ColdFusion server for this change to take effect.

Monday, January 07, 2008

ColdFusion 8 finalist among Dr. Dobb's Jolt Product Excellence Awards

Good to see ColdFusion 8 as a finalist in Web Development tools category among Dr. Dobb's 18th Annual Jolt Product Excellence Awards. Here is the entire story and here is the list of finalists.

Adobe ColdFusion IDE Survey

As part of our research on CF9 (Centaur), the ColdFusion team has come up with a survey to find out what features do you use and would like to have in an IDE for Coldfusion. Please take few minutes to take this quick survey.

http://www.surveymonkey.com/s.aspx?sm=321RrO9_2fWaP_2bdYMnmF9CuQ_3d_3d

Check out this space in few days for another survey to tell us what you would want to see in CF 9 !

Wednesday, January 02, 2008

Encrypted CFML Templates

Coming back from the 10 days shutdown period that we had at Adobe, I am catching up with the blogs and I read this interesting post by Ray where he mentioned that some one got his cfml templates encrypted and then lost the originals. Hmmm.. that is a situation, I would never want to be in. In case you have not figured it out yet, it is not possible to get back the original source. Let me explain.

Why do we need to encrypt cfml templates? To protect the cfml code and your intellectual properties (IP) in case you want to distribute your CF application. Right? In pre-CFMX7 era, ColdFusion used to have "cfencode" utility which used to encrypt the template which you can then distribute to anyone. ColdFusion used to know how to decrypt that and then how to execute that. However, this was not a good solution as people came up with utility to decode this encrypted file. And THAT means that  your code and IP was not protected at all. This had another disadvantage - template execution was slower as it meant decrypting the template first and then compiling/executing it.

With CFMX7, this changed. ColdFusion came up with sourceless deployment to make it nearly impossible to decode it back to the original source. When you use 'cfcompile' with deploy option, your cfml template is compiled to java byte code (class) but the file in which this byte code is written still retains the same template name. To give an example, if you run cfcompile on "hello.cfm", the output would still be "hello.cfm" but it will actually be java class file. To confirm this, just open one of such encrypted file in a hex editor and you would see the first 8 bytes will be CAFEBABE - the magic number for java class files. This file can then be distributed to your customers. For execution, ColdFusion works smart - when request comes for this template, it sees that it is not a cfml template but a class file, skips parsing and compiling the template, and directly proceeds with the execution.

As you see, there is no encryption and no key involved here. The encrypted file is simply a java class file and I have not heard of any utility that can decompile this class file back to cfm source. Though there are many Java decompilers available which can convert the class file to approximate java source file, it will be a huge huge task to write a decompiler which can generate cfm code for class file. One needs to know how CF does the code generation, know a great deal about bytecode instructions and apply lots and lots of heuristic to get the approximate cfm source. This is definitely not an easy thing to do even if some one breaks open the CF engine to see how it generates the java code from cfm code.

The bottom line is - in case you use sourceless deployment, ALWAYS backup your original source.