Friday, August 1, 2008

How to install POI on ColdFusion 8 using JavaLoader.cfc


Update (02/07/2009):

The new POI 3.5 beta also supports ooxml files (xlsx,docx,...). For updated instructions see: How to install the POI 3.5 beta on ColdFusion 8 using JavaLoader.cfc

Update (01/15/2010): Changed server scoped lock to named lock in Application.cfc example


I decided to write up a quick set of instructions for using POI with ColdFusion 8 as a reference. If you are not familiar with the JavaLoader.cfc it is a great tool, written by Mark Mandel, that allows you to dynamically load jar files.


Instructions:

1. Download the latest version of POI from http://poi.apache.org/. Extract the jars into the desired directory.

    Example:
    I created a directory under the webroot named "poi" and placed the jar files there. You can use a different location. So long as ColdFusion has permission to access whatever directory you select. Please note the jar file names tend to be based on version and date. So your file names may differ.

    Jar Locations:
    c:\coldfusion8\wwwroot\poi\poi-3.1-FINAL-20080629.jar
    c:\coldfusion8\wwwroot\poi\poi-contrib-3.1-FINAL-20080629.jar
    c:\coldfusion8\wwwroot\poi\poi-scratchpad-3.1-FINAL-20080629.jar

2. Download and install the JavaLoader.cfc, available at javaloader.riaforge.org

    Example:
    I installed the JavaLoader under the webroot

    JavaLoader Location:
    C:\coldfusion8\wwwroot\javaloader\JavaLoader.cfc
    C:\coldfusion8\wwwroot\javaloader\JavaProxy.cfc
    C:\coldfusion8\wwwroot\javaloader\lib\*.*

3. Instantiate the JavaLoader

Usage
// get a reference to the javaLoader
<cfset javaLoader = server[application.myJavaLoaderKey]>

Application.cfc
<cfcomponent>

<cfset this.name = "POIExamples">
<cfset this.sessionManagement = true>
<cfset this.loginStorage = "session">

<cffunction name="onApplicationStart">
<!--- use a unique hard coded key to store the javaLoader in the server structure ---->
<!--- the xxxx is actually a hardcoded UUID value ---->
<cfset var myJavaLoaderKey = "xxxxxx-xxxxxxxx-xxxxxxxxxx-xxxxxxxxxxx_javaloader">
<cfset var jarPaths = arrayNew(1)>

<!--- if the javaLoader was not created yet --->
<cfif NOT structKeyExists(server, myJavaLoaderKey)>

<!--- these are absolute paths to the POI jar files --->
<cfset arrayAppend( jarPaths, expandPath("./poi-3.1-FINAL-20080629.jar")) >
<cfset arrayAppend( jarPaths, expandPath("./poi-contrib-3.1-FINAL-20080629.jar")) >
<cfset arrayAppend( jarPaths, expandPath("./poi-scratchpad-3.1-FINAL-20080629.jar")) >

<!--- re-verify it was not created yet --->
<cfif NOT structKeyExists(server, myJavaLoaderKey)>
<cflock name="#Hash(myJavaLoaderKey)#" type="exclusive" timeout="10">
<!--- create an instance of the JavaLoader and store it in the server scope --->
<cfset server[myJavaLoaderKey] = createObject("component", "javaloader.JavaLoader").init( jarPaths )>
</cflock>
</cfif>
</cfif>

<!--- store the key in the appliation scope for easy access by other pages --->
<cfset application.myJavaLoaderKey = myJavaLoaderKey>
</cffunction>

</cfcomponent>

11 comments:

Murray,  December 16, 2008 at 8:16 PM  

Hi Leigh,

If anyone wants to know how to use the javaLoader with Ben Nadel's POI Utility custom tags, I have posted a blog entry here:

http://murrayhopkins.wordpress.com/2008/12/17/value-error-when-using-builtin-poi-in-coldfusion-mx7/

Cheers,
Murray

Hamlet,  December 31, 2008 at 7:23 AM  

I have a few questions:

1. Do you have to 'extract' all the jar files or just place them in the directory?

2. it says to 'install' the javaloader.cfc file - do you mean, just to copy it in the desired directory?

3. I keep getting this error for the javaloader.cfc file: networkClassLoaderClass = getServerURLClassLoader().loadClass("com.compoundtheory.classloader.NetworkClassLoader");

Please help, thanks.

cfSearching December 31, 2008 at 1:24 PM  

@Hamlet,

1. No you do not need to extract the contents of the jar files. Just place the jar files themselves in the desired directory.

2. Yes, just copy it into the desired directory. _But_ the javaLoader uses multiple files, not just the CFC. You must copy all of the files into the desired directory for the component to work properly.

The .zip file for the current version (0.6) contains two folders:

/examples
/javaLoader

Copy the entire /javaLoader folder to the desired directory. For example, I copied it directly beneath my webroot:

C:\coldfusion8\wwwroot\javaloader\

3. Your error is probably related to missing files. Try copying all of the files as mentioned above. That should resolve any errors.

-Leigh

Hamlet,  January 7, 2009 at 6:39 AM  

Hi - thanks for responding.

I now keep getting this error on the line:
<cfset document = createObject("java", "org.apache.poi.hwpf.HWPFDocument").init( inputStream )>

It says: Caused by: java.lang.ClassNotFoundException: org.apache.poi.hwpf.HWPFDocument

I tried it on both PC and Mac...by the way, will this poi work on Macs?

I'm not a Java developer, so I can't even begin to tell where the class would be...however, I did copy all the folders and files like you instructed. Any ideas would be greatly appreciated!

Thanks

cfSearching January 7, 2009 at 9:43 AM  

@Hamlet,

I now keep getting this error on the line:
<cfset document = createObject("java", "org.apache.poi.hwpf.HWPFDocument").init( inputStream )>


It is because you are using createObject(..) instead of javaLoader.create(..). When you use createObject() ColdFusion only searches for jars in the ColdFusion classpath. The built-in POI jar in the classpath is an older version that does not does not contain any of the hwpf classes. So that is why you are getting the "Class not found" exception. Use javaLoader.create(..) so ColdFusion will use the newer jars you downloaded instead. They do contain that class.

I'm not a Java developer, so I can't even begin to tell where the class would be

If you are curious, the built-in POI jars are located in the c:\ColdFusion\lib\ directory:

c:\ColdFusion\lib\poi-2.5.1-final-20040804.jar
c:\ColdFusion\lib\poi-contrib-2.5.1-final-20040804.jar

When you use createObject() those are the jars ColdFusion will use by default. Jars are essentially zip files. You can use a tool like pkzip, winzip, 7-zip to view the contents (Just do not extract them. They probably contain hundreds of classes ;-).

The class name "org.apache.poi.hwpf.HWPFDocument" is like a directory structure. It means that inside your POI jar, the class "HWPFDocument" will be located inside the subfolder: /org/apache/poi/hwpf. If you view the poi-2.5.1-final-20040804.jar you will notice that subfolder does not even exist. That is all the ClassNotFoundException means (ie the class file was not found ).


- Leigh

cfSearching January 7, 2009 at 10:30 AM  

@Hamlet,

by the way, will this poi work on Macs?

Theoretically, yes. It is java so it should be platform independent. Though I do not know from personal experience.

-Leigh

cfSearching January 7, 2009 at 10:33 AM  

> that does not does not
> c:\ColdFusion\lib\

Should obviously be > c:\ColdFusion8\lib\. My typos abound today ;-)

Hamlet,  January 7, 2009 at 10:57 AM  

Ahh - thank you. I made the change on the test code and it seemed to have done it. However, do I know change all my createObject(..) to javaLoader.Create(..)? The Application.cfc you showed us has the createObject and so does the javaloader.cfc - having said that, there's an error now on the javaloader.cfc on line 93 "var class = getURLClassLoader().loadClass(arguments.className);"

the error is similar:
java.lang.ClassNotFoundException: java

Thank you so much in advance,

Hamlet

cfSearching January 7, 2009 at 12:12 PM  

@Hamlet,


However, do I know change all my createObject(..) to javaLoader.Create(..)?

Yes, but just the ones in your own code and only the ones using the _java_ POI classes. Do not change anything in javaLoader.cfc, or it may not work properly. There is no issue with the Application.cfc because it is creating a "component", not a java object.

ie createObject("component", ..) rather than createObject("java", ..").

So the classpath problem does not apply.




there's an error now on the javaloader.cfc on line 93 "var class = getURLClassLoader().loadClass(arguments.className);"

That is be cause the javaLoader.create(..) expects different parameters than createObject(...). The javaLoader _only_ creates java objects, so you do not need to tell it the object "type" the way you do with createObject(). Just pass in the class name:

javaLoader.create("org.apache.poi.hwpf.HWPFDocument")

- Leigh

Hamlet,  January 7, 2009 at 1:02 PM  

Leigh,

You're a genius! I can't thank you enough for this blog. It worked just as you said it would.

You're probably the only one explaining CF and POI on the Internet right now - at least the only one I found in 2 weeks of surfing the web.

Thanks again, if there's anything I can do for you, please ask. I'm going to integrate this very important feature into a new website I'm creating www.iGetSpanish.com (still under construction).

Thanks again,

Hamlet

cfSearching January 7, 2009 at 1:47 PM  

@Hamlet,

I am very glad it was helpful! I know there are a lot more CF/POI resources out there now, versus a year or two ago. But as with many things, it is not always easy to find the right level of information that you need at the moment. So the more resources (to help bridge the gaps) the better. At least as far as I am concerned .. ;-)

- Leigh

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep