Receiving Flex Objects in Coldfusion, coldfusion component argument types

Flex Remoting with Coldfusion. Coldfusion Services and custom objects/components

I was getting frustrated when I COULD NOT receive a flex object as anything when a coldfusion service was receiving a remote call from flex. The coldfusion component had a method I was sending a call to. This method expected a struct arguement and then I was trying the argument type as on object. When I passed in the flex object to the remote method call in flex, when coldfusion received the argument it was breaking it apart and treating it as a messed up argument collection. Turns out you have to wrap a flex object in another object for coldfusion to receive it as a struct. Why the lack of documentation on this? I think flex remoting is really cool, but maybe it is a newer wave of development that just hasn’t been very popularized yet. I think that is changing.

In any case the following links really help with understanding how coldfusion and flex work together with remoting. Coldfusion components, like custom TO objects, can also be used across the wire, and vice-versa with flex objects. It is pretty slick, but you have to learn how to make coldfusion components and corresponding flex objects with properties that match, etc.

Nice article by Joel.

http://www.joelconnett.com/flexobjectstocoldfusion.html

I had originally found the following, which was helpful:

http://codingmurloc.wordpress.com/2007/05/15/passing-object-to-a-cfc-flex-or-cf-bug/

For custom component types, see also:

http://www.brucephillips.name/blog/index.cfm/2006/10/26/Exchaning-User-Defined-Objects-Between-ColdFusion-and-Flex

http://www.forta.com/blog/index.cfm/2006/2/1/The-Keys-To-Getting-CFC-ActionScript-AutoConversions-To-Work

Dynamic argument list with coldfusion methods using argumentCollection

Check out the link, and learn how to use pass arguments to Coldfusion methods using the argumentCollection as your parameter. This is slick.

I was doing the following, concatenating my argument list to change with logic. I should have been using an argument struct instead of a clumsy string that was being evaluated like this:


<!--- This is a not so cool approach--->
<cfscript>
argsColl = "";
argsColl &= "username=Almonzo,";
argsColl &= "password="LauRa123";
authorized = securityCFC.getAuth(Evaluate(argsColl));
</cfscript>

The following was so much cooler, cut my code down, and made it so I didn’t have to figure out why the Evaluate function won’t evaluate strings with commas:)


<cfscript>
argsColl = structNew();
argsColl.username = "Almonzo";
argsColl.password = "LauRa123";
authorized = securityCFC.getAuth(argumentCollection = argsColl);
</cfscript>

Helpful link:

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=buildingComponents_28.html

Multiple Coldfusion Instances as Windows Services using Multiple JVM configs and Debugger Settings

Summary:

Setting up each coldfusion server instance as a Windows service using its own jvm.config. Using the debugger with multiple coldfusion server instances causes errors unless you specify a separate debugger port in a unique jvm.config file for each instance.

First Note: If you can live with having no server instances running when you initially start windows, you can just start your cf server instance using the command line, with the -config option pointing to a custom config. The rest of this article focuses on setting up multiple jvm.configs, each coldfusion instance having a different jvm.config, and setup as a Windows services that can automatically start in windows.

jrun -config jvm.config_new_server -start default

After getting the following error repeatedly, I decided to stop putting up with running multiple coldfusion instances from one jvm.config file.

FATAL ERROR in native method: JDWP No transports initialized,

jvmtiError=AGENT_ERROR_TRANSPORT_INIT(197)

ERROR: transport error 202: bind failed: Address already in use

ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)

JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized

[../../../src/share/back/debugInit.c:690]

This error stemmed from me having multiple Coldfusion server instances, and every time I started one it would throw errors that a port was already in use (The debugger port). All my instances were setup to use the same debugger port, since they all used the same jvm.config file. I got sick of remembering to stop debugging services, or edit the JVM.config to not run the debugger each time I started a different CF Instance. Obviously there are many reasons for using separate jvm.configs, notably for allocating memory resources and settings to be shared more efficiently. Here is my step-by-step process for setting up multiple coldfusion server instances to run with multiple jvm.config xml files.

Note: If you use debugging with the default server, but do not change the default server instance to use its own jvm.config, from what I can tell, it still starts up fine, even though a port in use error shows up. I think this is because the admin server and the default instance server are both using the default jvm.config, but the admin server must not really cause enough of a clash to prevent the default instance from starting, since the admin server probably does not do that much with the debugger port. I need to explore what exactly the admin instance does. It is not as full blown as the other instances, and it must just serve as a shell or base that manages the other instances.

1)Go to Windows Admin Tools -> Services. Locate the name of Coldfusion Instances that are running as services. On my computer, these services show up as “Macromedia JRun Admin Server”, “Macromedia JRun CFusion Server” (The default instance, which for me was called cfusion) and “Adobe Coldfusion 8 AS cfusion2” (I set up another server instance called ‘cfusion2’). You need to remove all services for which you want to have a debugger. This way, you can remake the service with the option to use a specific and custom JVM. For example, you could have all instances use the default jvm.config, except for one.

2)Remove the non-default services that aren’t configured to use a custom JVM (unless you want the services already installed to just use the default JVM). Do this by using the jrunsvc.exe from the command line. Same folder as the default jvm.config. For me this was c:\JRun4\bin. So once you know the name of the services you want to remove, the command goes like this:

jrunsvc -remove “Adobe Coldfusion 8 AS cfusion2”

Don’t forget the quotes if there are spaces in the Service Name.

3)Install the instances as services, each one using the -config option to point to a custom JVM.config of your creation. Here are the commands I issued:

I left the default instance alone, and made the default JVM config contain the settings I wanted for the first and default instance (jvm.config). Here is the command for installing the second coldfusion instance as a service with a config file cfusion2.jvm.config:

jrunsvc -install cfusion2 cfusion2Service “cfusion2 Service” “This is the service for
the coldfusion server instance cfusion2” -config C:\Jrun4\bin\cfusion2jvm.config

And if you had a third instance, you could do

jrunsvc -install cfusion3 cfusion3Service “cfusion3 Service” “This is the service for
the coldfusion server instance cfusion3” -config C:\Jrun4\bin\cfusion3jvm.config

I know, very original naming. The install option is followed by 3 namings for the new service of my server instance. I think these are 1)service name 2)service display name 3)service description. These are arbitrary names and descriptions that the jrunsvc command has you set.

Note: I originally had the config option point to -config cfusion3jvm.config, but my service wasn’t getting my debugger port started, and I think it may have been using the jvm.config instead of the custom one. I changed -config cfusion3jvm.config to -config C:\Jrun4\bin\cfusion3jvm.config and it worked fine. Maybe I didn’t need to do that and I was just missing something though.

Note: If you try and start the service and get the ‘Windows could not start the service … review the System Event log … refer to service-specific error code 4″, or windows does not start the service, look in the event log (Admin Tools -> Event Viewer->System) and you’ll see the error from the Service Control Manager. The service-specific error is less than useful, but for me this meant that I did not get the path or the filename correct to the config file when I created the service.

4)If you specify different debugger ports for each CF instance, setup up a different debugger in your IDE for each CF instance, since one debugger can’t run on two ports (I would assume). This goes for anything else. If you configure different things in each JVM, you have to configure anything using the different instance settings to correspond.

Of course, if you don’t want to deal with all these services, and no server instances are running when you initally start windows, you can just start your cf server instance using the command line, with the -config option pointing to a custom config.

I think it is nice to have my 2 instances (soon 3 or 4), one for each dev environment, start up on their own when windows loads, each using a different port for a debugger. Too many instances running can really eat resources though.

Useful Links:

http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_18206&sliceId=2

Coldfusion Scheduled Tasks, single quote in task name screws server up

The errors from accidentally putting a single quote somewhere in a scheduled task name in the CF Server Admin start like this:

Server (my local dev server) may start up and serve cfm pages, but error log has a bunch of errors.

The CFAdmin gives you a “The Cron service is not available” error

The server error log shows “error while reading header <VARIOUS HEADER NAMES HERE>”

The neo-cron.xml is invalid xml

Resolution: Since you can’t get back into CFAdmin, replace the neo-cron.xml with the default one (This will delete all your schedules tasks, but you can recreate them after the cfadmin works again). Or you can correct the syntax erro

Returning an xml document from a coldfusion component – use cfcontent

So I was pretty annoyed how hard it was to find a description of how to return an xml document from a component back to an AJAX page that had sent a request to the component. I was making a simple form, and all I wanted was to make a simple call to a remoteService, and get a simple xml response. I didn’t really want an AJAX Framework/object for this simple task.

So after returning a simple string, the coldfusion service was adding the standard wddx xml tags around the string before it was received by the client page. So I learned you have to use a return type xml, instead of a return type string. But when I did that, even though the xml document looked well-formed, and how I had intended it to look with no wddx stuff, the receiving page was seeing null in the responseXML property of the XMLHttpRequest object.

So on this AJAX page, my XMLHttpRequest variable is called xmlHttp. And all I was getting was the xml doc as text in the xmlHttp.responseText property of the xmlHttp object. I wanted the xml doc to be in xmlHttp.responseXML and not the xmlHttp.responseText.

Using firebug (great FF add-on) I examined the reponse I was getting. Turns out the header of the response showed a content type of text/html and not an xml type. I finally figured out the key. In php yu could just add a header to set the content type to xml, using the header function. That is what I had been doing. Buth with coldfusion I had no idea how to add a content type header. THE KEY WAS IN THE CFCONTENT TAG. In my component being called, before I returned the xml object I had created, I learned you could just add a cfcontent tag to change the return type’s header.

<cffunction name="getSomethingInfo" access="public" output="false" returntype="xml">
<cfargument name="somethingID" type="string" required="true" />
<cfset var xml = "">
<cfquery datasource="adatasource" name="qThingInfo">
SELECT s2.*, u.* FROM Something s
INNER JOIN Something2 s2 on s2.userID = s.consultantID
INNER JOIN [User] u ON u.id = s2.userID
WHERE s.id = <cfqueryparam cfsqltype="cf_sql_integer" value="#somethingID#">
</cfquery>
<cfif qThingInfo.RecordCount EQ 0>
<cfxml variable="xml">
<noResults>
<requestSubject>SomethingInfo</requestSubject>
</noResults>
</cfxml>
<cfelse>
<cfoutput query="qThingInfo" maxRows="1">
<cfxml variable="xml">
<SomethingInfo>
<firstName>#UrlEncodedFormat(firstName)#</firstName>
<lastName>#UrlEncodedFormat(lastName)#</lastName>
</SomethingInfo>
</cfxml>
</cfoutput>
</cfif>
<!--- THIS IS KEY!!!--->
<cfcontent type="application/xml; charset=UTF-8">

<cfreturn xml />
</cffunction>

My code to send the request using a coldfusion component:

xmlHttp.open("GET", "RemoteServices/ARemoteService.cfc?method=getSomethingInfo"
+ cacheEntry , true);
// define the method to handle server responses
xmlHttp.onreadystatechange = handleRequestStateChange;
// make the server request
xmlHttp.send(null);

to call a coldfusion component and get a value from a method, the url for the request is:

PathtoYourComponent/YourComponent.cfc?method=yourMethodName&
param1=param1value&param2=param2value

Helpful Links:
http://www.coldfusionjedi.com/index.cfm/2007/2/8/Returning-XML-in-ColdFusion-for-AJAX

http://www.brucephillips.name/blog/index.cfm/2006/11/11/Use-ColdFusion-Function-Return-Type-of-XML-to-Provide-XML-to-Both-Spry-and-Flex

Element 1 is undefined in a Java object of type class coldfusion.runtime.Array

This error is thrown when you try and access an element in an Array that is undefined. How would this happen? Here’s what I did.

I wanted to make an array of 2 elements. I did this in a loop that ran 5 times. Instead of making an array of 2 elements, I made an array of 5 elements, only 2 of which were defined:

Here is the messed up array:

messed up array

So check your array, and make sure when it is being created that no undefined elements are created by skipping element assignments. Mae sure you don’t create an array, and then do something like:

<cfset items[3]="bbgun" />
<cfset items[5]="bb" />

Here, elements 1,2, and 4 will be undefined. Should be:

<cfset items[1]="bbgun" />
<cfset items[2]="bb" />

Coldfusion Unity Reactor – Default behavior for zero values and nullable columns

I noticed when I was unit testing that when I was setting a reactor record field to zero (userrecord.setUsedFilespace(0)), and then saving the record, the database would not update the table’s value from null to zero.

Turns out, as Chris pointed out, that if a table has a column that allows nulls, any zero value will automatically be saved as NULL. So this column,of type bigint, had no way of getting a zero value into it through reactor, which would always set the zero value to null.

What we did was customize the userDAO. We changed the create and update methods. In the DAO folder of the project, the userDAO was edited. In the create and update methods we changed the code:

null=”#Iif(arguments.to.usedFilespace EQ 0 OR NOT Len(arguments.to.usedFilespace)

TO

null=”#Iif(NOT Len(arguments.to.usedFilespace)

And this allowed the updates and creates to use zero values.

Accessing data in a coldfusion query object

The syntax is:

queryvariable.columnname[rownumber]

It would seem that the query datatype is an array of structs. Indeed as I read some posts online, I discovered a query is like an array of structs. But the query object is a special data type in coldfusion, like an array or a struct. See the Adobe article linked below.

I don’t know why this was so hard to find in the livedocs, or why the ColdFusion documentation for cfquery didn’t have any useful links, but Joel was able to point out to me right off that you can access the data in the rows/fields of a cfquery easily.

I’ll quote Adobe’s livedocs here, in a buried artilce. I ended up finding this useful page with a google search.

“A query object, sometimes referred to as a query, query result, or record set, is a complex ColdFusion data type that represents data in a set of named columns, similar to the columns of a database table.”

“You reference query columns by specifying the query name, a period, and the column name”

“You can access query columns as if they are one-dimensional arrays.”

Ex:<cfset myVar = myQuery.Employee[2]>”

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Variables_17.html