Wednesday, December 29, 2004

ColdFusion Webservice Issues

ColdFusion has been giving me fits for the last few days. I have been trying to publish a webservice using ColdFusion 6.1. At MAX 2003, they made it seem so simple.

Here are the problems that I encountered, and their solutions. I sure wish that these would have been documented somewhere. Incidentally, I am running ColdFusion MX 6.1, the full developer version, using the builtin webserver, on Windows XP Professional

Problems with changing the returnType
When I first started playing with the cffunction access="remote", everything seemed to be working OK. I did a simple web service with returnType="string", and which returned the following string: "test_string". Everything worked great. However, when I played with changing it to returnType="numeric", and tried to return 123456, I immediately started getting a rather bizarre error that looked something like this:

Could not perform web service invocation "test_function" because AxisFault
faultCode: {}Server.userException
faultSubcode: faultString: org.xml.sax.SAXException: Bad types (class
java.lang.String -> class [Ljava.lang.Object;) faultActor: faultNode:
faultDetail: {}stackTrace: blah,blah,blah....

This one took me a day and a half to figure out. Finally after a couple of hours on google, I learned the following. Turns out that when you change a component, you aren't necessarily changing the WSDL. ColdFusion creates the WSDL the first time that a component function is called as a web service, and then caches it away for later use. So, when you change your component, especially if you change the returnType, the WSDL and the way that the web service behaves no longer match. I don't know how long ColdFusion keeps this cache, but it is long enough to generate errors for several hours/days.

What you can do to alleviate this problem is to log into the ColdFusion Administrator, click on "Web Services" (under "Data & Services") , find the webservice that you changed, and click the "refresh" icon listed to the left of it. Doing so will refresh the WSDL so that you don't have to get this rather nasty error any more.

Problems with <cfinvoke>
I was never able to successfully consume the web service using cfinvoke. I don't know if it was a problem with the function that I was calling, or with the way that cfinvoke is implemented, but I never did get it to work right. However, I did have success using the following:

<cfset object_name = createObject("webservice","http://[path]/[component].cfc?wsdl")>
<cfset foo = object_name.test_function()>
<cfdump var="#foo#">

Problem with returnType="array"
I finally got the web service component publishing with returnType="string" and returnType="numeric". However, trying to get it to work with returnType="array" was giving me fits. Then after learning about the Administrator refresh, I finally started getting the following error:

I never actually did find an answer to this one on google, but I was able to figure it out. When ColdFusion creates an array, it is not just memory addresses like a simple array in C++. It is actually creating an array object that the variable name points to. When I was returning the array, it was just returning the pointer. Then after returning the pointer, it would destruct the webservice invocation, thus destructing the array, and the pointer was left pointing to nothing. So, I made the following change to my cfreturn, and now everything works just great (I wish that this would have been documented somewhere in big bold letters!):

<cfreturn variables.test_array>

<cfreturn duplicate(variables.test_array)>

Adding the "duplicate" changes the way that ColdFusion returns the variable.

This is a very important concept to understand. When you copy a complex variable from one place to another in ColdFusion, it doesn't actually copy the objects that the variable points to. It only copies the pointer. For example, let variables.test_array be an arbitrary array. Remember from before that variables.test_array isn't the actual array, it is only a pointer to an array. When you make the following assignment:

<cfset array_copy=variables.test_array>

you aren't actually copying the array. You are only copying the pointer to the array. Thus, if you make any changes to variables.array_copy, you also are making changes to variables.test_array; they are the same array or in other words, they are two names for the same thing. This is called a shallow copy.

However, if you want to make an actual seperate copy of the array, you have to use the "duplicate" function. Example:

<cfset array_copy=duplicate(variables.test_array)>

In the above example, you made an seperate copy of the array. This is called a deep copy. It actually goes through, and makes a copy of the array pointed to by variables.test_array, and all objects pointed to by variables.test_array.

For some reason, the in the XML of the WSDL document, the following appears in several places:


What does this mean? Can't say for certain. I think that it is a generic exception name used by ColdFusion to return debugging information in the event of an error.

Mounting a USB Drive / Thumbdrive on Linux

First of all, I am working with Mandrake 9.1, Kernel 2.4.21. this may be a lot easier under 2.6. Who knows. Also, I am using a Sony Microvault USB Thumbdrive. This should probably work with any other thumbdrive. But once again, no guarantees.

  1. Turn on computer.

  2. Log in.

  3. su to root. (I have not tried doing this without su-ing to root, although it may work.)

  4. Go to /mnt (is: "cd /mnt").

  5. Create a directory called "usb" ("mkdir /usb").

  6. Change the directory mode to be 777. ("chmod 777 usb")

  7. Go to /etc. ("cd /etc")

  8. Open up the file "fstab". ("vi fstab"). I am going to do this using vi. You are welcome to use any program that you wish. Also, be really careful with the fstab file. It is the file that tells your computer how to connect to different file systems, such as your hard drives, and your cd drive. fstab is pretty forgiving of any new stuff that you may add, but don't mess with any text that is already there.

  9. Go to the end of the file. (Press the down button until you are on the bottom line. Then press the "End" button on your keyboard.)

  10. Tell vi that you want to insert text. (Press the letter "i")

  11. Press the "End" button on your keyboard again. You should now be at the end of the last line of the fstab file.

  12. Create a new line by pressing the "enter" button on your keyboard.

  13. Type in the following, verbatim (leave out the quotation marks):

    "/dev/sda mnt/usb ext3,vfat defaults,noauto,users 0 0"

    (Make sure that you left out the quotation marks.)

  14. Hit the escape button on your keyboard. ("Esc").

  15. Press the colon button on your keyboard. (":")

  16. Type the following: "sav fstab".

    (Leave out the quotation marks.)

  17. Tell vi that you want to quit the program. (":q")

  18. Type in the following: "mount /mnt/usb".

    (Once again, leave out the quotation marks.)

  19. Your Sony Microvault is now mounted! If you are using Mandrake 9.1, there is now a picture of a hard drive on your desktop. You can access the microvault thru this icon.

This same procedure should work with other USB Mass Storage drives (not just the Sony Microvault.)