Application.cfc onRequestStart() Called Twice

I spent a bit of time tracking down why I kept seeing two exact same threads (run by thread()) being run simultaneously. These threads are spawned by FrameWork One’s (FW/1) setupRequest() method. After tracing the methods with some console dumps, doing some research via Google and process of elimination, I finally got a clue.

Let’s say I hit http://mysite.com and this site requires a login. If you are not logged in lets saw we use a location() call to get to the login page. I also use a log-in imitator via a UI to see how different account look under their login, which also uses the location() method. Because of these location() calls, the onRequestStart method is called once before the redirect and once after the redirect.

Now, thinking I can overcome this by wrapping the thread() call in if( !isDefined( “myThreadName” ) ). However – apparently the onRequestStart calls come so quick that the thread name isn’t created in time to be detected. So two threads are still spawned.

I could probably add a flag to the session scope wrapped in a lock operator. However what happens if the thread is terminated manually? This may not be the best option, but it’s not bad as long as your site admins are aware of that consequence.

In this case I’m going to reassign my statements to my log-in handler instead of my setupRequest() method and call it good.

Let me know if you have any other ideas on how to handle this. I’m all ears.

NECFUG FW/1 Presentation

In July 2012, I presented to the Nebraska ColdFusion User’s Group on the topic of FrameWork 1 (FW/1) for ColdFusion. Thanks to Ryan Stille for recording this.

Also be sure to check out “A crash course in MVC with FW/1” with Steven Neiland as this provides a much better method for presenting this topic.

Continue reading

Framework One AJAX Method (FW/1)

NOTE: This is now obsolete. Use the method renderData() instead.

I really haven’t found a method I like that returns JSON via FW/1 until I saw a presentation by Steven Neiland the other day. Basically you have a few choices:

  1. Call a service directly: This leaves you w/o any FW/1 features and the service is not initialized.
  2. Create views that return JSON: This can become tedious and seems unnecessary, but FW/1 features are available
  3. Have onMissingView handle it: Views do not need to be created and FW/1 features are available

My approach uses #3.

Example jQuery AJAX call:

$.ajax({
	url: 'index.cfm?action=products.attributesAJAX',
	type: 'GET',
	dataType: 'json',
	data: {parentPartNumber: $('#productForm').data( 'parentpartnumber' )}
});

You’ll notice it requests the section “products” and the action “attributesAJAX”. We will not create the view for the action, but we will create the controller method for it.

component {

	function init( FW ) {
		variables.FW = FW;
		return this;
	}

	// AJAX
	void function attributesAJAX( required struct RC ) {
		FW.service( 'productService.getProductAttributes', 'data', { parentPartNumber = RC.parentPartNumber } );
	}

}

To return JSON data w/o creating a view, we let the Application.cfc’s onMissingView method handle the return:

function onMissingView( required struct RC) {
	// if a data key exists, assume this is for AJAX and render as JSON
	if ( structKeyExists( RC, "data" ) ) {
		request.layout = false; // turn off default layout
		new services.utility().showDebugOutput( false );
		getPageContext().getResponse().getResponse().setContentType('application/json');
		return serializeJSON( RC.data ); // convert data to JSON
	} else {
		return view( 'main/pageNotFound' ); // set view to the missing page message
	}
}

You’ll notice that if the view’s missing it looks for the RC.data value. If it exists it assumes you want to return JSON back. Otherwise it will call the “pageNotFound” view (which you need to create). Note how the layout is turned off, it calls a method to turn off debugging (for development), and sets the content type to JSON.

This is the utility I created to turn off debugging:

<cfcomponent output="false">

	<cffunction name="showDebugOutput" output="false" returntype="void">
		<cfargument name="switch" default="false" type="boolean">
		<cfsetting showdebugoutput="#arguments.switch#">
	</cffunction>

</cfcomponent>

Returning Distinct ColdFusion Entities

Take this code example:

return ORMExecuteQuery(
	'FROM user U
	JOIN U.stateLicenses
	WHERE U.company.id IN (:companyIDs)'
	,
	{
		companyIDs = arguments.companyIDs
	},
	false,
	{ ignorecase = true }
);

Each user can have multiple state licenses, thus what we get back here is an array of array of entities that have duplicated users.

Lets take a couple of steps to fix this.

1. Change “JOIN U.stateLicenses” to “JOIN FETCH U.stateLicenses”. This will give us an array to work with instead of an array of an array. It also brings back the licenses right away. I didn’t investigate why this is though.
2. Add “SELECT DISTINCT U” to the beginning of the HQL. This will return distinct user records with an array of licenses. This fixes our duplicate users situation.

The modified working code is:

return ORMExecuteQuery(
	'SELECT DISTINCT U
	FROM user U
	JOIN FETCH U.stateLicenses
	WHERE U.company.id IN (:companyIDs)'
	,
	{
		companyIDs = arguments.companyIDs
	},
	false,
	{ ignorecase = true }
);

#hql

FW/1 ColdSpring Services That Rely On The Prior

In FW/1 you have the variables.fw.service method to work with in your controllers. This method will run your service’s method and return the results to a key inside the RC scope. Keep in mind, however, these service calls are queued up and not run until the view is called. Why this is done I have no idea, but I’m sure there’s a reason.

Because they are queued, something like this would return a variable not defined error:

variables.fw.service ( 'users.get', 'userRecord' );
variables.fw.service ( 'geographic.getStatesByCountry', 'states', { userID = userRecord.getUserID() );

So after spending some time reading through threads on Google Groups, I determined the old fashioned way is the best way. However there’s a nice feature if you have a bean service defined such as ColdSpring. This feature implicitly sets a property named the same as a defined bean in your XML configuration. For example:

component accessors = true {
  property usersService;

  function init ( FW ) {
    variables.fw = arguments.fw;
    return this;
  }

  void function default ( RC ) {
    RC.performerRecord = getUsersService().get ( ID = 1 );
    variables.fw.service ( 'geographic.getStatesByCountry', 'states', { userID = userRecord.getUserID() );
  }
}

You don’t need use the fw.service on the last call, but I left it in there … just because.

What happens is FW/1 will look to see if each property defined matches a bean definition. If found it automatically sets the property to the bean. Otherwise you’d normally put something like this into your init:

setUsersService ( application.beanfactory.getBean ( "users" ) );

FW/1 and Service Beans in ColdSpring

Recently I started switching from a Model-Glue implementation with ColdSpring to FW/1 (Framework One) with ColdSpring on a project of mine.

An example service bean definition looks like this:

<bean id="geographic" class="geographicService" />

With the new FW/1 code, I tried calling a method in this service by using:

variables.fw.service ( 'geographic.getStatesByCountry', 'states' );

But ended up with this error:

Service ‘geographic.getStatesByCountry’ does not exist. To have the execution of this service be conditional based upon its existence, pass in a third parameter of ‘false’.

After hours of debugging, my team member finally found a solution; change the bean id from geographic to geographicService. Apparently FW/1 automatically appends “Service” to the bean ID it references so that it can cache services and controllers that way. This appears to be lacking in the FW/1 documentation, or at least clearly.

So the fix is:

<bean id="geographicService" class="geographicService" />

#beans, #coldfusion-2, #coldspring, #framework, #fw1

Console Logging of ColdFusion ORM SQL

If you read my post on getting the ColdFusion Builder Console working and use ORM, you may have run into some further questions.

When generating ORM, it’s wise to monitor what SQL queries Hibernate is generating for you, both for performance and debugging reasons. (Wasn’t ORM supposed to make my life easier?).

To start logging ORM’s SQL set this property in your application.cfc:

<cfset this.ormsettings.logsql="true">

You’ll may notice however that the default configuration will not show DDL queries used for creating or updating tables nor will it show the parametrized values (just a ?).

To enable these things look at <cf_home>\lib\log4j.properties (in my case it’s C:\ColdFusion9\lib\log4j.properties).

To enable logging of parametrized values uncomment and change the value for log4j.logger.org.hibernate.type to look like this:

log4j.logger.org.hibernate.type=DEBUG

It seems like a little overkill on what this ends up returning because not only will it return your parametrized values but also what each column returns. I wish I could disable the latter.

To enable logging of exports and updates (DDL) uncomment and change the value for log4j.logger.org.hibernate.tool.hbm2ddl to look like this:

log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG, HIBERNATECONSOLE

I placed an example snippet below. Thanks to Rupesh Kumar for providing this information.

#sql-queries

SQL to ColdFusion ORMType Reference

I have not been able to find a good reference chart out there that maps SQL Data Types to ColdFusion ORM Data Types. It’s always really been my best guess. So I’m going to start a reference chart here that as I figure it out I’ll update. If you have any input on this please comment and I will update. Thanks!

ORMType SQL MySQL
big_decimal DECIMAL, MONEY DECIMAL
binary BINARY, VARBINARY TINYBLOB
blob TINYBLOB
Boolean [SMALLINT], BIT BIT
clob LONGTEXT
date DATE DATE
double DOUBLE, MONEY, NUMERIC DOUBLE
character, char CHAR
float REAL, FLOAT FLOAT
integer, int INT INT
long BIGINT BIGINT
serializable TINYBLOB
short SMALLINT SMALLINT
string CHAR, NCHAR, VARCHAR, NVARCHAR VARCHAR
text TEXT, NTEXT LONGTEXT
timestamp DATETIME, SMALLDATETIME, TIMESTAMP DATETIME
true_false CHAR
yes_no CHAR

Camel Case for Two Letter Acronyms

Here’s another “for later reference”…

Microsoft’s rules for .NET Framework 1.1 Abbreviations consist of:

  • Do not use abbreviations or contractions as parts of identifier names. For example, use GetWindow instead of GetWin.
  • Do not use acronyms that are not generally accepted in the computing field.
  • Where appropriate, use well-known acronyms to replace lengthy phrase names. For example, use UI for User Interface and OLAP for On-line Analytical Processing.
  • When using acronyms, use Pascal case or camel case for acronyms more than two characters long. For example, use HtmlButton or htmlButton. However, you should capitalize acronyms that consist of only two characters, such as System.IO instead of System.Io.
  • Do not use abbreviations in identifiers or parameter names. If you must use abbreviations, use camel case for abbreviations that consist of more than two characters, even if this contradicts the standard abbreviation of the word.

These appear to be good guidelines to follow for ColdFusion as well. I was going after casing for two letter acronyms in this case.

REF: http://msdn.microsoft.com/en-us/library/141e06ef(v=vs.71).aspx

Looping Over Arrays in ColdFusion 9.01 (CFScript)

This is pretty much a “note to self”… but in ColdFusion 9.01 you can now loop over arrays using the  for – in loop while in cfscript.

Syntax is:

for(item in array) {
    doSomething(item);
}

#array, #arrays, #coldfusion-2