Friday, November 20, 2009

Mpls CFUG - Active MQ, Cluster Messaging, Topics and

I'll be presenting at the Minneapolis / St. Paul ColdFusion User Group again in December on Active MQ, Topics, Queues and Cluster Messaging for those interested. I'd love to pack the room before Christmas and show off all the exciting things Apache's Active MQ messaging can do with your ColdFusion applications, especially as it relates to cluster messaging. I'll be doing live demo's and code shows, as well as discussing how our company has used these techniques to help us address things like cache updating/invalidating, message driven events, maintenance queues, workflow etc.

Visit the ColderFusion.com website for more details but hope to see you out December 2, 1009, in the mean time, check out my new keyboard!

Updated: Download the code samples and presentation (+code) (requires activemq and blazeds deployed on tomcat as separate downloads) OR download the Entire thing with blazeDS, tomcat, amq and code in one large 200MB file

New Bluetooth Keyboard

I broke down and got one of the new Logitech deNovo Edge Keyboards from Amazon this week. I'm just breaking it in but so far it's very sweet. The sleek lazer cut plexiglass and brushed aluminum frame is very 'edgy', and at 11 mm thick, you'll feel like your on a laptop even when docked. It's even got a little touchpad so you can throw your mouse out if you want (but I wouldn't recommend that as the left/right click buttons are not large enough to make it full time usable). It will be perfect for the home theater remote keyboard when you have a PC hooked up to your system.


As you could tell from a prior post, I was wearing the 'C' letter out on my last keyboard, and having a quieter keyboard with cool functionality was something I was definitely interested in.
If you're out shopping this Black Friday, maybe you'll get lucky and see one on sale, but Amazon has it for a discount right now.
Happy coding - !

Wednesday, September 23, 2009

Model Glue - Variable CTRLINST is undefined

I'm playing around with Model Glue 3 (gesture) and event-types and message handling etc, and I ran across a nasty little productivity stopper.

I had defined an 'init' method which did nothing in my Model-Glue Controller for one of my controllers. I was getting a very obscure 'Variable CTRLINST is undefined.' message as a result.

<cffunction name="init" output="false" access="public" returntype="void" hint="">
<cfreturn />
</cffunction>


Removing the 'init' method from the controller solved the problem, and the error message went away - leaving me to run my application once again.

I had become so accustomed to putting an 'init' method regardless in all cfc's that If I had not had some prior controller code to look at - I would have been sitting on this error for a long time.

Hope this helps someone out there - Maybe a more appropriate message here would help (framework guys).

Monday, August 24, 2009

100+ Downloads for CFProperty Inspector ColdFusion Builder Extension

I made it past the 100+ downloads barrier for the ColdFusion Builder (pre-release) IDE with my CFProperty Inspector Extension. Thanks to all who've downloaded it and found it useful. Not bad numbers (10% download to view ratio) considering the IDE is not going to be released for another month or more.

Keep an eye open for more updates on the future as requests come in for the next version of the extension which allows you to write cfproperty tag meta data to existing components.

Thursday, July 23, 2009

Search Engine Death Match (Pt. 3) MPLS CFUG

I'll be speaking to the Minneapolis/St. Paul ColdFusion User Group (CFUG) on Aug. 6, 2009 about the Solr Integration in ColdFusion 9 (Centaur Beta). If you're in the area we'd love to see you, session starts at 6:30 - more information at ColderFusion.com.

Preview:
Search Engine Death Match: Solr (Luncene) vs. Verity

Search is King.
See how the 2 engines that ship with ColdFusion 9 stack up.
Learn more about the newly integrated Solr (based on Java Lucene) engine and how it stacks up against Verity.
Listen to real world stories about Solr's performance in a large scale Enterprise application.
Preview the features of Solr in Centaur Beta and determine if you're company could benefit from a better, more scalable, more reliable search solution.

Here is a preview of the session (pdf).

Hope you see you there!

Thursday, July 9, 2009

cf_PropertyInspector Bolt Extension Released!

Version 1 of the cf_PropertyInspector ColdFusion Builder/Bolt Extension for your IDE has been released on riaforge (pending).

Features Include:
For ease of Flex Integration, CFProperty tags are needed to have your methods available to ActionScript classes. Also complex webservices need this metadata defined for them. With existing components already created, having to go back in and add in all these cfproperty tags for all your 'accessors' is a pain. How about just right clicking -> 'Inspect CFC' and be done with it?? Best used if components exist under your webroot.

Features:
- Searching subdirectories
- Alpha sorting properties
- Wverwriting/keeping existing properties
- Lower case properties
- Exclusion of Methods (i.e getInstance, getBinaryNull etc)


Version 2 of this application will include the following:
- Backups of cfc's before modification
- Fine Tune properties before wizard completes
- Mapping support if your components are not located under your webroot.


Requirements:
ColdFusion 8+
ColdFusion Builder (Beta 2+) Build: 240677

Download NOW Available on riaforge.





















Final Result!

Sunday, May 17, 2009

Disable CFC Type Check Proof

I usually question a lot of the things I hear, and this one I just had to set the record straight. I can stand being corrected on things when I'm proven wrong so I'm hoping this will come across as simply a clarification and not any kind of 'I told you so'.

But in the CFADmin in CF8 'Settings' there is a 'Disable CFC type Check' option that allows you to turn ON the ability to ignore the argument 'types' of CFC's. For example, if I have a component of type 'com.adobe.reactor' and I pass that to a method expecting a 'com.adobe.transfer', if this option is ON, then there would be NO type checking and the argument would be successfully passed in (I'd assuming something else would fail after that however).

At cfObjective this year it was stated at a session that if this option was turned ON, a datatype like 'numeric' would be able to accept a 'string' value as there would be no type checking. This is simply not true

Proof:

Visit your cfadmin and turn ON the 'Disable CFC Type Check' option and restart your server.
Run the following script:


<cffunction name="test" output="false" access="public" returntype="any" hint="">
<cfargument name="num" type="com.adobe.transfer" required="true">
<cfreturn>
</cfreturn>

<cfset x="test('hi')">
<cfdump var="#x#">


You'll notice that this works just fine. Notice that I'm passing a string of 'hi' into the test method that is expecting a 'com.adobe.transfer' object. This works just fine with Disable CFC Type Checking ON as it simply treats the argument type as an 'ANY' type.

The CFAdmin states:
"When checked, UDF arguments of CFC type is not validated. The arguments are treated as type "ANY". Use this setting in a production environment only."


In this case 'com.adobe.transfer' is a UDF or user defined argument - I defined it in a directory of com/adobe/transfer.cfc.

However, when I change my test method to accept a 'numeric' value instead of this UDF value, you will see it will throw an exception:


<cffunction name="test" output="false" access="public" returntype="any" hint="">
<cfargument name="num" type="numeric" required="true">
<cfreturn>
</cfreturn>


"The NUM argument passed to the test function is not of type numeric."

This proves that ONLY UDF arguments are changed to 'ANY' types when 'Disable CFC Type Check' is turned ON in cfadmin (oh no I've gone cross eyed)

Imagine the security holes created by such an option if indeed the native datatypes were all treated as 'ANY'? SQL Injection could occur if you had typed the cfargument as a 'numeric' datatype. A malicious user could simply pass in a string value and bypass your initial line of attack - that being your cfargument data type. This would not be a good situation (more information on security and cfml see Jason Dean's blog at 12Robots.com).

The fact is, regardless of whether or not 'Disable CFC Type Check' is ON or OFF in your CFAdmin Setttings, native Datatypes still need to be adhered to, or an exception will be thrown.

Monday, May 4, 2009

A ColdFusion Developers Keyboard

How can you tell what kind of developer you are by your Keyboard??

Check out my keyboard - Notice the 'C' key is all but worn right off - This has been from about 2 years of programming on this external keyboard - My previous laptop was the same way!

Just for fun, shoot me a picture of your keyboard - whether ColdFusion Programmer, .Net Programmer or dba (would your 'S' key be worn down from all the SELECTS?).

Enjoy

Friday, May 1, 2009

Clustered Application Needs Re-Loading? Here's How

A question came up at last years cfObjective in Mike Brunt's presentation about reloading your application/model/ColdSpring config in mid-flight on a clustered application (your application has 2 or more CF instances running it).
We've spent some time investigating on our own and mostly just ignoring the issue and going through the tedious process of RDP-ing into the server and MMC-ing into each Servers Services Panel and restarting each instance and verifying they come back online - staggering them throughout a period of time until all cluster members were synced. This sucks.

Some of the proposed solutions included:
1.) Using ActiveMQ and a CF Gateway to Broadcast a 'reload' message and have the cluster members stagger their execution of it so they all don't reload at once (taking the app offline) via a thread sleep randomly based on the JVM instance etc.
2.) Appreloading via the url X times until you think you've HIT them all
3.) Use JRun's internal Web Server

I figured I'd give number 3 a try as I knew it would be the quickest and easiest to implement if it worked. Turns out it does.

What would happen is this: each CF instance has it's own dedicated IP and port that is running the application that can be accessed via a browser or over http (which can get automated but we'll get into that later).

The IP:Port is normally used if you wanted to get to a particular cluster members cfide to do some configurations etc i.e. 127.0.0.1:8303/cfide/administrator/index.cfm. However, if you browse to just 127.0.0.1:8303, you'll notice a nice directory structure that comes form your installation instance directory i.e. C:\JRun4\servers\{instancename}\cfusion.ear\cfusion.war if on Jrun.

So what we'll do is modify your jrun-web.xml file by adding the virtual root path to your application AND make sure if you use a separte jvm.config for your instance, that the default jvm.config is the same (more on that later).

Navigate to C:\JRun4\servers\{instancename}\cfusion.ear\cfusion.war\WEB-INF and open jrun-web.xml (if you don't have one you can try borrowing one from the default cfusion instance).

Add the following to the file and save:
<virtual-mapping>
<resource-path>/</resource-path>
<system-path>C:/webroot/approot</system-path>
</virtual-mapping>


This will make JRUN's internal web server root be your application's root directory.

Restart your CF instance.

If you are like most shops and use some kind of query parameter to execute your application reload procedure i.e. ?reloadsite=true or the like, then you can execute it via the ip:port?param and reload each cluster member by changing your ip:port.

Advanced Note: if you're like us and have a separate jvm configured for your CF instances (different than the stock jvm.config found in c:\JRun4\bin) then you'll need to make sure that
a.) either the jvm.config is the same as your CF Instance jvmconfig file
b.) make the jvm.config (default) the same as the CFInstance jvmconfig file, and then reconfigure that instance to use the 'jvm.config' file. This is key, as the internal JRun webserver will use the default jvm.config on startup, so if you have separated these jvm's out, reloading your app from ip:port will do nothing, as you have only just setup 2 separate jvm's running your application, and the one has NO knowledge of the other.

This is one method anyway - just make sure you have tested this thoroughly, especially if you have environment specific configurations that get loaded up depending on the url - as the IP address block may load up an unexpected set of configuration data from your application.

We'll be trying this out over the next few weeks and likely integrate it into the application in some kind of threaded reload routine if some configuration needs to be done mid-flight.

Enjoy!

Search Engine Death Match - Solr Wins (Pt. 2)

Abstraction:
They key to the integration of Solr and removal of Verity in our model was to abstract the search functionality of the application. The process started by creating a 'CollectionManager' which held the methods that were needed to interact with the Verity Server through cfsearch and consolodated all calls to 'cfsearch' through this service.

Coldspring:
Once that was done and working fine - we were ready to dive into Solr and figure out the nuances of the product and ultimately create a 'SolrManager' which would replace the collectionManager. Since we were using ColdSpring, this was a mere class path change in the coldspring.xml and that was it (I love ColdSpring).


Solr Data-Config:

I'll get a more formalized presentation together about swapping out Verity in favor of Solr, but in general, our data was in a SQL Database vs. xml etc, so we used the 'data-config.xml' to basically come up with our main query that populates the index (each solr instance has a single instance or collection vs. verity where there is 1 verity and many collections) as well as delta and delete queries for updating and removal of the collection data through JDBC. This data-config.xml file is simply an xml file in which you write sql to select your columns based on some criteria.
Note: it's best to have created, lastmodified, id, active columns in your database table you wish to index, as this will help Solr in determining what data has changed, and what has been deleted. Hint: keep these queries simple and use a 'view' if your sql is complex at all, as it will hide the complexity, making the file easier to read, and abstract the data in a way that you can change the view w/o having to change the data-config.xml file each time. It's also worth pointing out that the 'server time' should be exactly the same on both your database and solr machine (if not on the same box) as Solr stores internally the last time it indexed your data in a value referenced in your sql as '${dataimporter.last_index_time}'.
** If you have a 'smalldatetime' value for lastmodified where sql will 'round' the seconds of the field, then you may run into issues where Solr won't pick up on changes that have happened since it's last_index_time as compared to your database timestamps etc.

Solr Schema:
This is basically the data definition in a single schema.xml of your data. You define your 'fields' which are your columns of data from the data-config and the datatypes etc. This is very flexible including the ability to 'group' multiple fields together as a single field (copyfield) as well as defining what is the default field that's searched on if none is specified in the field (i.e. search for 'MN jobs' could search job titles, job desc, locations etc).

Solr Config:
There was a one line change here just to tell Solr to use the data-config for it's data:
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>


ColdFusion:
Wayne Graham has published an open source component out there at Ria Forge to assist in the low level cfhttp calls called SolManager. I've added this as a helper to my main 'SolrManager' component and i just call it to do the cfhttp calls to Solr and then I can do what I need with the data it returns.
Since the data is returned as xml, and the 'schema' of the data defines which columns / nodes are returned, I then have full control over the result. I convert the xml to a query using query new, xmlparse, and xmlsearch - and for our purpose as long as the query is in the same format as the one returned by a cfsearch through verity, the application won't know any difference.

Performance:
FAST! Solr does it's own caching and warming of searches and results and from my metrics, depending on the xml result set (which can EASILY be adjusted to limit the size of the xml as a '&rows=x' query string attribute in the search string) the performance is negligible if not better across the board for searches.

There's a lot more to discuss such as search syntax, replication, admin dashboard etc, but I'll leave a few stones un-turned for you to dive in and get your feet wet. They have good documentation on the site as well as an Extremely easy and efficient Jetty package that you can start up, execute a few commands on through a tutorial on their site, and get a feel for what to expect.

All in all, we were to the point where Verity was NO LONGER AN OPTION or a viable solution for our company and was causing nearly hourly baby sitting, so this solution was implemented JIT (Just in Time) and has saved us from feeling the effects of daily search stress.

Have fun and stay tuned for a full run down with code samples at MN CFUG soon.

Thursday, April 30, 2009

Search Engine Death Match - Solr Wins

It's now been over a month since we rolled out our Lucene / Solr powered search engine replacement for Verity in our application and let me sum it up this way: Zero maintenance.

Even though the OEM Verity licensing states 250K record max, we ran into a ceiling on a few of our machines when the number of Verity collections reached 82-88. We were doing constant rcadmin fixes to drop the thread counts for each collection down to 2 from 3 - but on each restart or at random points in time, the thread counts would return to 3. Instability and random collection switches were the main reasons we moved off the platform, and we'll never look back.

Solr took some configuration, but it was more than flexible enough for our needs, and with the delta updates and deletes, it made the maintenance near zero.

As far as parsing the resulting xml, that was done efficiently through coldfusion's xmlparse and xmlsearch to walk the nodes and return a 'like' verity recordset to the application. With ColdSpring we were able to swap out implementations easily and everything just worked. Great planning and execution resulted in a seamless rollout with Solr being run on RedHat on a dedicated machine.

I will most likely do a presentation at our next/upcoming CFUG (ColdFusion User Group) in Minneapolis/St.Paul in the near months about the transition and talk about integration points before ColdFusion 9 comes out and makes it all available with a single tag ;)

Long Live Open Source software

Tuesday, February 3, 2009

Query of Queries is Inconsistent (Adobe CFML Runtime)

I've never been a big fan of a half baked solution, but I will acknowledge that coldfusion's query of queries has come a long way from it's beginning and does do a good job on simple queries to get data from an existing query.

However, there are times when it simply sucks at doing what you think it should do, especially when it comes to multiple tables and joins, as well as converting datatypes to be alike.

I'll show a few examples of it's inconsistencies and attempt to point out some problems with it's implementation.

Example 1: Q-of-Q (Query of Queries) and Proper variable scoping inside a cffunction.

When inside a cffunction you always want to fully qualify your variables as best practice. If it's an arguments, prepend the value with 'arguments.' etc. The same goes for Q-of-Q. But I will show you where q-of-q forces you to break it's own best practice advice by not allowing you to do this simple task.

I will be referencing the following 2 queries:

<!--- Test Query 1 --->
<cfset q = QueryNew('id,name','Integer,varchar')>
<cfset queryaddrow(q,1) >
<cfset querysetCell(q,'id',1,1) >
<cfset querysetcell(q,'name','test',1) >

<!--- Test Query 2 --->
<cfset q2 = QueryNew('id,age','Integer,Integer')>
<cfset queryAddRow(q2,1) >
<cfset querySetCell(q2,'id',1,1) >
<cfset querySetCell(q2,'age',33,1) >


This is a simple query that creates a single row of data




What I'm going to do is merge the results of these 2 queries (as one may have come from a cfdirectory, and the other from a cfsearch, or cfquery etc).

My method takes 2 query arguments and joins them - but for now I'll just return the value of the 1st argument 'qry'.

<cffunction name="merge" output="false" access="public" returntype="query" hint="">
<cfargument name="qry" type="query" required="true"/>
<cfargument name="qry2" type="query" required="true"/>
<cfset var Private=StructNew()>

<cfquery name="private.q" dbtype="query">
select *
from arguments.qry

</cfquery>

<cfreturn private.q />
</cffunction>


Resulting in a simple query returned - nothing special.



Now when i wish to merge the 2 queries - I would assume that I could do something like this then if 'arguments.qry' worked to reference the qry argument.
<cffunction name="merge" output="false" access="public" returntype="query" hint="">
<cfargument name="qry" type="query" required="true"/>
<cfargument name="qry2" type="query" required="true"/>
<cfset var Private=StructNew()>

<cfquery name="private.q" dbtype="query">
select *
from arguments.qry, arguments.qry2
where arguments.qry.id = arguments.qry2.id

</cfquery>

<cfreturn private.q />
</cffunction>


WRONG!
Query Of Queries syntax error.
Encountered "arguments . qry .. Incorrect conditional expression, Expected one of [like|null|between|in|comparison] condition,

Ok fine - I won't use proper best practices and just reference the query w/o the arguments proper fully scoped value.

<cffunction name="merge" output="false" access="public" returntype="query" hint="">
<cfargument name="qry" type="query" required="true"/>
<cfargument name="qry2" type="query" required="true"/>
<cfset var Private=StructNew()>

<cfquery name="private.q" dbtype="query">
select *
from qry, qry2
where qry.id= qry2.id

</cfquery>

<cfreturn private.q />
</cffunction>


Results: works fine



Example 2: Using QofQ (query of queries) to reference a column from the table using dot notation

The ColdFusion LiveDocs states the following:
Example

If a structure named A contains a field named B, which contains a table named Products, you can refer to the table with dot notation, as follows:

SELECT tape_ID, length
FROM A.B.Products;



The 'structure' in my case is 'arguments', the field name is 'id', and the table name is 'qry'. With that in mind:

A=arguments
B=id
Products=qry

Therefore you could deduce that the following is true:


SELECT id, name
FROM arguments.id.qry


Results:

Query Of Queries syntax error.
Encountered ". Incorrect Select List, Incorrect select column, arguments.id cannot be followed by '.'


However, you would normally reference this data as 'arguments.qry.id'.

Results:

Query Of Queries syntax error.
Encountered ". Incorrect Select List, Incorrect select column, arguments.qry cannot be followed by '.'

The kicker is - Neither of these work.

Wednesday, January 28, 2009

Killer WDDX - Beware!

I came across a rather interesting 'feature' tonight while working on some logging and alerting processes. We have data in a structure that holds raw information about various processes that have occurred. In one of the structure keys there is an XMLObject (coldfusion parsed xml object). See the code snippet below and DO NOT run this on production equipment!!

<cfset stcStruct = StructNew()/>

<cfset xmlDoc = "<myxml><name>Kevin Penny</name></myxml>">
<cfset stcStruct.xml = xmlParse(xmlDoc)/>
<cfset stcStruct.id = 1>

<cfwddx action="cfml2wddx" input="#stcStruct#" output="tmp"/>


This takes a Structure, adds a key of 'xml' and places a parsed xml object in it's position. I'm then serializing the data into wddx via cfwddx as cfml2wddx.

I originally thought it was the date fields that I had in the structure, so I removed those, but the problem was the xml object's serialization.

Here's the error I get along with a partial dump:
java.lang.StackOverflowError

....
at java.beans.Introspector.instantiate(Introspector.java:1438)
at java.beans.Introspector.findExplicitBeanInfo(Introspector.java:410)
at java.beans.Introspector.(Introspector.java:359)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.(Introspector.java:368)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.(Introspector.java:368)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.(Introspector.java:368)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.(Introspector.java:368)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.(Introspector.java:368)
at java.beans.Introspector.getBeanInfo(Introspector.java:222)
at java.beans.Introspector.getBeanInfo(Introspector.java:208)
at coldfusion.wddx.BeanSerializer.writeObject(BeanSerializer.java:48)
at coldfusion.wddx.WddxOutputStream.writeObject(WddxOutputStream.java:310)
at coldfusion.wddx.BeanSerializer.writeObject(BeanSerializer.java:120)
at coldfusion.wddx.WddxOutputStream.writeObject(WddxOutputStream.java:310)
at coldfusion.wddx.BeanSerializer.writeObject(BeanSerializer.java:120)
at coldfusion.wddx.WddxOutputStream.writeObject(WddxOutputStream.java:310)

I've submitted this as a bug to Adobe #75230.

Wednesday, January 14, 2009

Update to CFPROPERTY Inspector Utility

I implemented a new UI for the CFPROPERTY Inspector as well as small bug fixes etc.

I used the JQuery tab UI which helps the flow of the steps being that the process is just one large form. Here are the new screen shots.










Tuesday, January 6, 2009

CFProperty Inspector on RiaForge

I've released the CFPROPERTY Inspector on riaforge and google code for those interested in it.

This Utility is designed to introspect components and auto-create CFPROPERTY tags based on the function meta data.
Specify the mapping to your components, and choose which cfc's you want to have CFPROPERTY Tags defined on them as well as what properties of your components that you wish to have CFPROPERTY tags defined for. (for assisting in getting your components well defined for Flex integration etc.)


For Screen Shots and more checkout cfproperty.riaforge.org and to download the code visit Google Code here.









Let me know what you think.