Category: ColdFusion

Mar 23 2010

Installing CF Builder as a Plugin on a Mac? Watch out for this...

After getting odd non-code highlighting issues, mylyn issues etc...

I happened upon this - http://blogs.adobe.com/cfbuilder/2010/03/things_to_watch_out_while_inst.html

The key line is "For Mac OSX, cocoa version of eclipse is not supported.Make sure that you use carbon version of eclipse."

made all the dfference for me.

2 comments - Posted by Jonathan at 1:03 PM - Categories: CFBuilder | ColdFusion

Feb 22 2010

The Best Bad Code Eva!

Not sure if I could find a worse way to accomplish this...

On the page we have:

<cfset my_date = mycomponent.ConvertStringToDate(stringDate = form.this_date)>

And the cfc it is calling has this method:

<cffunction name="ConvertStringToDate" access="public" output="false" returntype="any">
    <cfargument name="stringDate" type="string" required="true" hint="send id to return single item">
    <cfquery name="getDate" datasource="#mydsn#">
        Select to_date('#arguments.stringDate#', 'mm/yyyy') as newDate
        from dual  
    </cfquery>
    <cfreturn qDate.newDate>
</cffunction>   

The CFC is not even a "utility" component or such. It is something like a "user" object.

I LOVE IT!

I have made all variables generic to protect the guilty.

3 comments - Posted by Jonathan at 8:47 AM - Categories: ColdFusion | Oracle | SQL | Software | Stupidhead

Feb 19 2010

Caveat about (I just waisted 2 hours of my life because of that tag)

Here is how my day has gone so far

I am debugging an issue with a application view that is killing my local server.

I am calling a get() method from a component and the server hangs, never to return.

WOW! That must be a nasty query. Yes, Yes it is.

Well, slightly nasty. I got my queryparams in place, so that's not the issue. Actually,  not that nasty at all. Several sizable tables (i have select * for tables - i know, i Know, bad practice. but this is 4 year old code)

Hmm... maybe I am missing something.

Let's go talk to the dba and have her fire up their monitoring. Almost no activity coming from the Coldfusion Server.

Hmmm... (again).

Run the query directly against the database? OK, response is immediate.

Fire up CF Server Monitor.

How! Request is super slow but the memory usage is through the roof! 700MB

Does lots of queryparams (espesially used with list and WHERE IN cluases) cause memory useage?

Google...

Nothing.

Try to simplify query, just to test...

Still timesout.

What?

What is this that I see?

<cfdump var="#queryResult#">

right before the <cfreturn queryResult>

Ooooooohhhhhhhhhh!!!

I must have thrown that in once for debugging but just switched the Output attribute of the function to "false" and left that cfdump tag in.

In most cases, that's not a problem or at least not noticable. But this query (being slightly nasty as I stated earlier and containing select *) contained a lot lot lot of data, and in some cases, returns a bunch of rows.

So leason learned

Apparently, throwing debuging info into a component's method and then turning off output does indeed keep it form being outputted to the page, BUT it does not prevent it from actually being generated.

In this case it was a very large record set and so the cfdump output was huge.

I am still not sure why it caused THIS MANY problems. I have dumped huge objects onto a page and, while slow, did not just Kapowee the server.

But from now on I am going to be a little more deciplined in how and when I dump debugging info within CFCs

1 comments - Posted by Jonathan at 7:27 AM - Categories: Oracle | ColdFusion | Debugging | Performance | General | Stupidhead | SQL

Jan 27 2010

Select * from a Query of Query --> Craziness Ensues

I just spent way too much time debugging a very odd QoQ issue.

Read more...

3 comments - Posted by Jonathan at 1:14 PM - Categories: Debugging | ColdFusion | General | SQL | Query of Queries

Jan 5 2010

A File and Its Method: Planning out and implementing Server Specific Variables in your Applications

Here is the problem...

I want errors to be sent to the screen in development. I want errors sent to me via email in testing and production. I want the "contact us" email address to be mine in development and testing, but the client in production. I want all cfcs to be cached on every request in development (not cached, essentially) but not in testing and production. I can go on if you want, but that's just more reading for you. 

Simply put, I want my application to act slightly different in different environemnts. I didn't even bring up running the application locally.One way is to edit the code directly in each environment (really bad). Another is to have a config file in each environment (not as bad). But if you are like me, working in an enterprise environment, both of those options simply may not be possible.

Due to our change management policies, I have no control over anything after development, so hard coding anything is out of the question. Deploying different files in different environments would be possible but a terrific headache.

Solution One: cf-server.xml

I have in the past deployed an xml file to the root of each server that would handle how applications would handle several basic things. Mostly, when to cache cfcs and handle errors. The problems I had were these:

  • That xml file got overwritten on various deployments  and would end up being incorrect
  • It was very limiting.  It was per server and very few settings
  • I did not give a specific application its own settings. Sometimes I wanted it to handle caching or debugging differently than another (causeing bullet point 1)

Solution Two: Context.cfm and getContext()

Ok, once again I got this idea from Rails. Looking at the database config file where each environment is listed with all the connection information specified. That, of course, would not work in our enterprise environment due to developers not being privy to database login credentials apart from development. But it is a cool idea. Plan up front!. So why not do something like that?

So, first off, and I have said this before, we have our own framework. It's part MVC but not really and part OOP but not really. Very lightweight and pretty pwerful for building apps at warp speed. I am the primary developer managing the framework. So I get to be creative with it.

So this solution is going to be in the next release.  I have a working example and I think it would be pretty easy to implement regardless of how you are building apps. It also only took me about 30-60 minutes to build it in and start using from the point I got the idea. And I am pretty excited about it.

A File and a Method

It basically requires a file and a method in the Application.cfc file.

The idea is to create what I am calling an application context ( I have been using Railo a bit so "context" just popped into my head)

The File

Start by adding a context.cfm file to your app in an appropriate place. For example:

/yourdomain/config/context.cfm

This will will layout your different environments and for each environemnt, the server name and the list of variables you want instantiated.

Here is an example:

~Local
server:localhost
refresh:everytime
wak:/
error:screen
email:hold
status:true
deploy:none

~Testing
server:test
refresh:everytime.multipliedbyinfinity.com
wak:\
error:email
email:hold
status:true
deploy:none

~Prod
server:www.multipliedbyinfinity.com
wak:\
refresh:manual
error:email
email:send
status:false
deploy:manual

 

To give you and idea of what these settings are doing...

  • Wak - windows vs unix (yes I know there are better ways of doing this
  • Refresh - when and if to cache your apps cfcs
  • error - send to the screen with a big ol cfdump or pleasant error message and email big ol cfdump
  • email - send out emails generated by the app or not
  • status - the framework creates a status.cfm file that lets you know what cfcs got created automatically and if there were any errors along with other settings and info. Locally and development, let me just access it. in PPRD and PROD make it password protected or just not accessible
  • deploy: deploy.cfm will export the entire app from svn to the server. make it accessible just in development

You get the idea, right?

The Method

Here is the method that uses this file:

 

<cffunction name="getContext" access="public" returntype="struct" output="false">

    <!--- get the file root so we can cffile the context.cfm file --->
    <cfset fileroot = replaceNoCase(getbasetemplatepath(), "index.cfm", "")>

    <!--- which environment are we in? --->
    <cfset thisServer = cgi.server_name >

    <!--- read the file --->
    <cffile action="read" file="#fileRoot#/myAppLocation/config/context.cfm" variable="config">
   
    <!--- create a sturcture to hold the data --->
    <cfset context = structNew()>

    <!--- loop thorugh with the ~ delimiter  --->
    <cfloop list="#config#" delimiters="~" index = "i">
       
      <cfset server[i][1] = listFirst(i, "
    ")>

     <!--- set the enviroment (local, test, prod..)  --->
    <cfset currentEnv = listFirst(i, "
        ")>
    <!--- set the server of the environment you are looping through --->
    <cfset currentServer = listLast(listgetAt(i,2, "
        "), ":")>

      <!--- if the current server matches the servername in the this file, this is the set of variables that you need to instatiate --->
    <cfif thisServer eq currentServer>
   
    <!--- loop through all the variables and values and set them as elements in the stucture --->  
    <cfloop from="2" to="#listLen(i, "
            ")#" index="s"

         <cfset setting = listGetAt(i, s, "
                ")>   
        <!--- this is the  context.variable = value function--->
        <cfset context[listFirst(setting, ":")] = listLast(setting, ":")>
   
    </cfloop>
        <!--- go ahead and set the file type--->
        <cfset context.fileRoot = fileRoot>

    </cfif>
  
</cfloop>

<cfreturn context>

</cffunction>
Two things, yes I forgot to var scope the variables. on todo list. And not using chr() is sloppy.
 
So now add a call in your OnApplicationStart() method:

application.context = getContext();

Whammo!

You now have a structure in the applicaiton scope called context and you can start using it to decide how your app should work

<cfif application.context.debug eq "screen">
    <cfdump = "#foo#">
<cfelse>
   <cfmail/>
</cfif>

4 comments - Posted by Jonathan at 9:00 PM - Categories: Ruby on Rails | ColdFusion | General | Software | Framwwork | Subversion | Railo

Dec 14 2009

Real-world example of using CFTHREAD to Kick Major... (with screencast)

CFTHREAD, as dangerous as it is, rules. When trying to find exactly how to use this, I had a hard time finding simple examples. So, now that I have figured out how to use it (or at least get it working without blowing anything up), I thought a simple example would be helpful to others.

The Setup Up

This is a financial forcasting application. Coldfusion powers the transactional part, Business Object handles the reporting. The data model is a hybrid between a transactional database and a datawarehouse. User logs in, records daily actuals for line items for multiple banks. User also generates projections based on previous years acuals. User then hops over to Business Objects and can do real time reporting and analytics based on the transactional data they just managed.

Esentially we have the following:

  • x number of banks (Funding Sources)
  • x number of line items (children of banks, currently 250 or so)
  • x number of scenarios (these are projections (projected numbers based on previous year) and those are created elsewhere

There is a specific value for each day for each line item for each bank for each scenario...

about 6000 rows/ per month / per scenario.

The Problem

The problem with this setup is that while my application can determine future balances fine, Business Object needs to have that data in an actual database table. Think data warehouse.

We tried views and views of views, marterialized views, functions in oracle. Performance was horrible due to the complexity of the data. To give you an idea, our first and worst attempt took 4 minutes to bring back 84 rows! I posted a while back an article about using the database for the heavy lifting. I am going to reverse myself here a bit. We ended up taking it out of the databsae and using Coldfusion to update the future balances table.

Bottom line, we have to determine the future balances of each bank based on the projected values of the bank's line items and we need to then populate the "balances" table with the calculated balance.

The Process

So here are the steps we are taking:

  1. Clear out balances for Bank / Scenario following the last known actual balanace
  2. Get all actual line items for that bank
  3. Get a list of dates from last known balance to last known projected transaction
  4. Loop through each date, get the sum of all inflows and out flows since last known balance
  5. Apply the difference to the balance
  6. Store calculated balance into the database
  7. Repeat

The Code

Here is the code running this process without threading. View a screen cast of this in action HERE. I added a ";->" after each commit to the database for show.


<cfset syncFromDate = createDate(year(now()), month(now()), 1)>
<cfset qBanks = application.com.fundingSource.get()>

<!--- loop thorugh banks --->
<cfoutput query="qBanks">
   
    <h2>Syncing #qBanks.name# (#qBanks.id#)</h2>
    <p>
    <cfflush>
       
        <!--- get last know date with actual balance for this bank--->
        <cfset lastKnownCalendarID = application.com.balance.getLastKnown(qBanks.id).id>
        <!--- get a list of all future dates that have transactions --->
        <cfset calendarIDList = application.com.balance.getFutureDates(fundingSourceID=qBanks.id, scenarioID=sid)>
        <!--- clear out balances for this bank/scenario so its clean for the new round of data--->
        <cfset exec = application.com.balance.clearFuture(
                            funding_source_id=qBanks.id,
                            scenario_id=sid )>
   
    <!--- loop through dates --->
    <cfloop query="calendarIDList">       
   
    <!--- this function inserts the calculated balance (cf calling an oracle function) and then adds a record to the balances table with value--->
    <cfset exec = application.com.balance.add(
                    end_balance=application.com.balance.getCalculatedBalance(fundingSourceID=fsid, scenarioID=sid, calendarID=id),
                    funding_source_id=qBanks.id,
                    scenario_id=sid,
                    calendar_id=id,
                    is_Actual_Balance=0,
                    added_by=0)>                   
        <!--- silly --->
        ;-> <cfflush>
       
       
        </cfloop>
        </p>
</cfoutput>
   
<p>Balances Synced</p>

Now the same process but using threading. I added some comments specfically about using cfthread. You can see the Screencast in action HERE




<cfset syncFromDate = createDate(year(now()), month(now()), 1)>
<cfset qBanks = application.com.fundingSource.get()>

<!---
    I am going to create a handful of threads, run them and then join them at the end
    create a threadList variable with a comma delimited list so that at the end you can indeed join them
--->

<!--- create a variable to store all the thread ids --->
<cfset threadList = "">


<cfoutput query="qBanks">

    <!--- append each bankID to the thread list so the script know which threads to join at the end --->
    <cfset threadList = listAppend(threadList, qBanks.id)>
    <h3>Syncing BANK (#qBanks.id#)</h3>
    <cfflush/>
    

    <!--- create a thread for each bank, use the bank id as the thread id, and pass in the bank id from the query as "bankID" --->
    <cfthread action="run" name="#qBanks.id#" priority="LOW" bankID="#qBanks.id#" >
        <cfset fsid = bankID>
        
         <!--- now run throught the same process as non-threaded but they will all be done asynchronously --->
        
        <cfset lastKnownCalendarID = application.com.balance.getLastKnown(fsid).id>
        <cfset calendarIDList = application.com.balance.getFutureDates(fundingSourceID=fsid, scenarioID=sid)>

        <cfset exec = application.com.balance.clearFuture(
                            funding_source_id=fsid,
                            scenario_id=sid )>
    
        <cfloop query="calendarIDList">        
    
        <cfset exec = application.com.balance.add(
                            end_balance=application.com.balance.getCalculatedBalance(fundingSourceID=fsid, scenarioID=sid, calendarID=id),
                            funding_source_id=fsid,
                            scenario_id=sid,
                            calendar_id=id,
                            is_Actual_Balance=0,
                            added_by=0)>                    
        </cfloop>
        </p>
    </cfthread>
</cfoutput>

<!--- Lastly, now that all the threads are created and running, wait till they are all done, join them back together and go on your merry way --->
    
<cfthread action="join" name="#threadList#" />

<!--- done! --->
<p>Balances Synced</p>

So there you go! It took very little code to make this process mulit-threaded and asynchronous. If you look at the time of each screencast you can see it took about 1:30 to run thorugh the whole process without threading and about 10 seconds with threading.

Warning!

There are dangers using threading. Read up on them before going to far down this road. Basically, you have to balance the speed you want things processed with how much your cpu can take. It's pretty easy to take down a server with out of control threading. Also, if you are running through this kind of massive insert/update process MAKE SURE YOU ARE WRAPPING EVERY DYNAMIC THING IN QUERYPARAMS. Initially I had one value that was not wrapped and it took down Oracle. (granted, it was the 6000 insert statements for creating the projected data)

Hope this helps. I am no expert with threading. far from it. but this is how i am using it in a real world project.

2 comments - Posted by Jonathan at 7:23 AM - Categories: ColdFusion | Oracle | Threading | Performance

Dec 10 2009

Subscribe

Categories

Monthly Archives

Search Archives

Favorite Links

My Links

Coldfusion Links

Recent Tweets