Matt Woodward’s posterous

Matt Woodward’s posterous

Matthew Woodward  //  * CFML, Grails, and Java Developer
* Principal IT Specialist, US Senate
* Open BlueDragon Steering Committee Member
* All-Around Geek

Mar 7 / 11:44am

New OpenBD Goodies: SpellCheck Plugin and RenderInclude() Function

In addition to the CronPlugin there are a couple more additions to Open BlueDragon this weekend: a SpellCheck Plugin, and a RenderInclude() function.

As you might guess from the name, the SpellCheck Plugin allows you to check the spelling of text from within your CFML applications. It ships with an American English dictionary, but you can register your own dictionaries in either OpenOffice format, Mozilla XPI format, or use a simple array of words.

Usage couldn't be simpler:

<cfscript>
textToCheck = "Pleze chek mi speling.";
results = SpellCheck(textToCheck, "english-us");
</cfscript>

SpellCheck() takes the text to check and the dictionary (or multiple dictionaries) against which to check the text, and it returns an array of structs with these keys:

  • originalWord - the misspelled word
  • positionIndex - the position of the first character of the misspelled word in the string being checked
  • suggestedWords - an array of strings that are suggested corrections for the misspelled word
Very slick and easy way to add spellcheck capabilities to your CFML applications.

The RenderInclude() function is a CFSCRIPT version of the CFINCLUDE tag so you can include templates within CFSCRIPT and have the code in the included template be rendered and returned as a string.

<cfscript>
renderedOutput = RenderInclude("/path/to/template.cfm");
</cfscript>

All the new functionality that has been added to OpenBD in the past few months has been an incredible asset to my CFML development, and I'm really excited to see more and more plugins being created. Plugins are an easy and extremely powerful way to add new functionality to the OpenBD engine. Reminds me that I need to get back to work on my CFTWITTER plugin to finish that out!

Filed under  //  CFML   Open BlueDragon  

Comments (1)

Mar 6 / 9:18am

CronPlugin for OpenBD

From OpenBD

Jump to: navigation, search

Category:CronPlugin

The CronPlugin makes the management and scheduling of tasks much easier within OpenBD.

Inspired from the simplicity of the /etc/cron.d/ subdirectories, this plugin brings the ease of that method to the CFML developer by allowing them to simply drop files into pre-defined folders that will be automatically run, without needing to wrestle with external scheduling jobs or CFSCHEDULE.

The plugin will automatically create the necessary directories if they do not already exist. You set this directory by making a call to CronSetDirectory(). This directory location will persist over server restarts.

For example making a call with:
CronSetDirectory("/cron.d")
will create the following directory structure within the web app directory.
/<webapp>/
/<webapp>/cron.d/cron.5min/
                /cron.15min/
                /cron.hourly/
                /cron.daily/
                /cron.weekly/
                /cron.monthly/

After this, you can simply drop .cfm files into each of these directories and they will be run at the allocated time. There is no need to restart the engine, or re-call the CronSetDirectory(); it will automatically be picked up.

Everytime the plugin executes one of these files at the desired time, a copy of the output is retained. Within the OpenBD working directory, a similiar structure is created but under the plugin-cron directory, where you can view the results of each file.

This plugin triggers the main OpenBD CFML engine directly, without having to go out and back in via HTTP. This makes it highly efficient and removes a lot of the overhead associated with other schedule methods.

This plugin operates with the nightly build post 4th March 2010 and can be installed by simply copying the .jar file into the /WEB-INF/lib/ folder of your web app.

[download the plugin]

Pages in category "CronPlugin"

This category contains only the following page.

C

Another awesome plugin for OpenBD. Some really slick possibilities here, and my favorite thing is that FINALLY we have a way to run scheduled tasks without them simply being a scheduled HTTP call. The CronPlugin processing the CFML code in the engine directly.

Note that this doesn't replace the traditional scheduling, but it's another option that will work really well for a lot of use cases.

Filed under  //  CFML   Open BlueDragon  

Comments (0)

Jan 31 / 7:09pm

CFQUERYPARAM Reuse With QueryRun() in Open BlueDragon

I'm working on an application with a friend of mine and we're taking full advantage of all the great new functions and features in Open BlueDragon. One of the new functions I wasn't sure I'd use all that much is QueryRun(), which lets you run a query in a CFSCRIPT block like this:

<cfscript>
  QueryRun(datasource, sqlStatement, queryParams);
</cfscript>

Let's look at a concrete example. Assume a table called "user" with fields of id, email, first_name, and last_name, and a datasource named "myDSN". To pull all the users, you'd do this:

<cfscript>
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user";
  users = QueryRun("myDSN", getUsersSQL);
</cfscript>

Now if you want to pull a specific user--let's say by email--you can parameterize your queries by using an array of structs that represent the CFQUERYPARAM tags, where the key in each struct is the attribute name from CFQUERYPARAM, and the value for each key is the value of the CFQUERYPARAM attribute. Things start looking a bit Java-esque with the question marks, but here's how that works (and note use of the newly added implicit array and struct notation):

<cfscript>
  getUsersSQLParams = [{value = "matt@mattwoodward.com", cfsqltype = "cf_sql_varchar", maxlength = 100}];
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user ";
   getUsersSQL &= "WHERE email = ?";
  users = QueryRun("myDSN", getUsersSQL, getUsersSQLParams);
</cfscript>

Let's go over what's going on here. First, in the struct contained in the getUsersSQLParams array, you can see the familiar attributes of value, cfsqltype, and maxlength from CFQUERYPARAM. Next, notice the ? in the SQL statement. Any question marks in your SQL statement will get replaced in the order in which they appear by the structs contained in the SQL parameters array. So in this case, that ? in the SQL statement essentially becomes a CFQUERYPARAM with the key/value pairs in the struct defined two lines above.

To reinforce this point, let's look at an example pulling a user by first name and last name:

<cfscript>
  getUsersSQLParams = [{value = "Matt", cfsqltype = "cf_sql_varchar", maxlength = 100}, 
                     {value = "Woodward", cfsqltype="cf_sql_varchar", maxlength = 100}];
  getUsersSQL = "SELECT id, email, first_name, last_name FROM user ";
  getUsersSQL &= "WHERE first_name = ? AND last_name = ?";
   users = QueryRun("myDSN", getUsersSQL, getUsersSQLParams);
</cfscript>

In that case I have two parameters in my SQL statement represented by two question marks, the first of which is replaced by the first struct in the SQL parameters array (corresponding to first_name), and the second is replaced by the second struct in the array (corresponding to last_name).

While working on this application I came across an added bonus with this way of doing things that I didn't really consider when the feature was first added to Open BlueDragon. Since your query parameters are stored in an array of structs as opposed to being added to each query as individual CFQUERYPARAM tags, you can re-use the query parameters across multiple queries.

When would this come in handy? Consider basic CRUD operations, specifically inserts and updates. In many cases the only difference between an insert and update is a "WHERE id = ?" clause, but using CFQUERY you wind up having to repeat a ton of CFQUERYPARAM tags between the two queries.

By using QueryRun() and the array of structs that represent the query parameters, these parameters can be reused between an insert and an update operation. This example is fairly trivial since the table is so small, but you can imagine how much redundancy you save on large tables.

<cffunction name="save" access="public" output="false" returntype="void">

  <cfargument name="user" type="User" required="true" />
 
  <cfscript>
    var commonSQLParams = [{value = arguments.user.getEmail(), cfsqltype = "cf_sql_varchar", maxlength = 100},
                           {value = arguments.user.getFirstName(), cfsqltype = "cf_sql_varchar", maxlength = 100}, 
                            {value = arguments.user.getLastName(), cfsqltype = "cf_sql_varchar", maxlength = 100}];

    // if the ID is 0 do an insert, otherwise do an update
    if (arguments.user.getID() == 0) {
       var insertUserSQL = "INSERT INTO user (email, first_name, last_name) ";
          insertUserSQL &= "VALUES (?, ?, ?)";
      var insertUser = QueryRun("myDSN", insertUserSQL, commonSQLParams);
     } else {
      ArrayAppend(commonSQLParams, {value = arguments.user.getID(), cfsqltype = "cf_sql_integer"});
      var updateUserSQL = "UPDATE user SET email = ?, first_name = ?, last_name = ? ";
           updateUserSQL &= "WHERE id = ?";
      var updateUser = QueryRun("myDSN", updateUserSQL, commonSQLParams);
    }
  </cfscript>
</cffunction>

Since the update statement only needed the one additional WHERE parameter of the ID, I can just append that to the end of the SQL parameters array I created from the data in the user object and re-use the rest of the parameters for both queries.

Personally I think that's pretty darn slick, and although at first the ? notation may seem a bit odd at first (at least if you aren't used to doing things that way in Java), you wind up with some very concise code when using QueryRun() due to the ability to reuse the SQL parameters across multiple queries.

Filed under  //  CFML   Open BlueDragon  

Comments (1)

Jan 29 / 7:01am

Implicit Array/Struct Creation and new Operators in Open BlueDragon

Today sees the release of some much awaited support for both implicit array/struct creation and a whole host of operators. The cfscript and expression parsing engines have been rewritten, switching from the javacc based parsers to a cleaner and leaner ANTLR based one.

Check out all the details on the OpenBD blog!

Filed under  //  CFML   Open BlueDragon  

Comments (0)

Jan 28 / 8:04am

Running ColdFusion Under a Service Account on Windows Server and Null Pointer Errors

I was installing ColdFusion 8.01 on a new Windows Server 2003 VM yesterday, and since the application that will be running on this box needs access to network shares I had our network admins create a new domain service account under which to run ColdFusion. This is pretty commonplace for a lot of our apps, but for some reason when I switched the CF service to run under the service account I started getting a 500 error with the following details when any .cfm page was hit:

 

java.lang.NullPointerException
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:285)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

This was even after I had assigned "full control" rights to the service account user to the application directory.

I asked around a bit since I'd never seen this before, and Dave Watts came up with the solution. (Thanks Dave!) In this case I logged onto the server via remote desktop using the service account, at which point I was forced to change my password. After I changed my password, the remote desktop login didn't proceed because that user didn't have RDP rights on the server. I didn't think that was an issue, but Dave suggested that there might be a problem if the service account didn't have a local profile created on the server, which of course happens the first time a user logs in.

I gave the service account RDP rights, logged in as that user, the local profile was created, and everything works now. So if you see null pointer errors when trying to run CF using a service account, this might be your problem.

Filed under  //  CFML   ColdFusion   Windows  

Comments (0)

Jan 26 / 7:34am

Comparing Two Arrays in CFML

This came up yesterday in a discussion with a friend of mine. He had two arrays and he wanted to see if they were identical in terms of order and value of the elements. His first thought was to loop through the arrays and compare each element, but since CFML arrays are really Java arrays, there's a much simpler way.

<cfscript>
arrray1 = ArrayNew(1);
array1[1] = "foo";
array1[2] = "bar";

array2 = ArrayNew(1);
array2[1] = "foo";
array2[2] = "bar";


arraysAreEqual = array1.equals(array2);
</cfscript>

The equals() method on the array returns a boolean and tells you whether or not the arrays are identical in terms of the values and ordering of the array elements. Note that if the values are identical but in a different order, the arrays will not be considered equal, so sort before doing this test if there's a chance things might be in a different order between the two arrays.

Filed under  //  CFML   Java   Open BlueDragon  

Comments (3)

Jan 16 / 8:45am

OpenBD gets native JSONP support

However, what if you wish your services to be consumed by a Javascript function outside of your own domain? Cross-domain scripting will prevent this. So how do the likes of delicious.com offer such Javascript integrations for their services?

You achieve this by using JSONP (JSON with Padding) and this lets you achieve cross-domain data fetching.

JSONP requires a little assistance from both the server and the client inorder for it to work. JSONP works by wrapping the returning JSON packet in () and prepending a name to make it into a Javascript document.

The majority of Javascript libraries support JSON from their native core. JQuery supports it using $.getJSON method, which simply asks that you append the URI parameter "callback=?" to the end of the remote URL and it will do all the marshalling of data for you.

Another extremely slick addition to OpenBD! It's available in the nightly build. Read more at the full blog post (link above).

Filed under  //  CFML   JavaScript   JSON   Open BlueDragon  

Comments (0)

Jan 15 / 3:04pm

Twitter Plugin for Open BlueDragon

I finally got a chance to put some time in on a Twitter plugin for Open BlueDragon, and I'm happy to report it's coming along very nicely! The plugin API for OpenBD is really easy to dig into so I thought a Twitter plugin would be as good an exercise as any to get my feet wet. I'm planning a series of blog posts illustrating how to write plugins for OpenBD using the Twitter plugin as an example, so look for that before long.

If you aren't familiar with the plugin API for OpenBD, this is a really slick way for you to add tags and functions to OpenBD that become available natively within your OpenBD instance. The plugin code is written in Java (don't worry, it's not daunting at all), and you then drop a JAR file into your WEB-INF/lib directory. When OpenBD fires up it detects the plugin, registers the functions and tags contained within the plugin, and they're then available for you to use in your CFML code.

You can learn more about the plugin API on the OpenBD wiki, and Alan Williamson also has a great blog post about it. Note that you can do much more than add tags and functions; you can also listen for events occurring inside OpenBD itself and act on these events, and even call CFCs from within your plugin. Very powerful stuff. OpenBD ships with a plugin for IRC, and spreadsheet, wiki, and JavaScript plugins are also implemented via the plugin architecture, and they're available on the OpenBD download page.

But I digress. ;-) The main reason for this post is to give people an overview of how the Twitter plugin is working thus far, but more importantly to ask for your help. Creating a Twitter object with a TwitterNew() function and subsequently calling methods on that was really easy, but of course we CFMLers love our tags, so I also created a CFTWITTER tag. What I don't want to do, however, is add an ACTION attribute to the CFTWITTER tag for every method available on the object, so if people have thoughts on how they'd like the tag to work I'd love some opinions.

So what can you DO with the Twitter plugin for OpenBD? Well, pretty much anything you can do with the Twitter API. Basically I took the excellent jTwitter Java library and rolled that in the OpenBD plugin, and this exposes Twitter functionality natively to CFML. Here's some examples.

<!--- create a new twitter object --->
<cfset myTwitter = TwitterNew('username', 'password') />

<!--- get your friends timeline --->
<cfset timeline = myTwitter.getFriendsTimeline() />
 
<!--- set your status --->
<cfset status = myTwitter.setStatus("Hello from OpenBD!") />

<!--- search twitter --->
<cfset searchResults = myTwitter.search("openbd") />
 

You get the idea. I've implemented all the methods listed in the jTwitter javadocs, but I'll have documentation for the plugin when I make it available to download. (And hey, if you're a really, really early adopter, email me and I'll send you a copy!)

As for the tags, this is where I need your help. To me it makes complete sense to do this:

<cftwitter action="login" 
               screenname="foo" 
               password="bar" 
               variable="myTwitter" />
 

But the path I don't think is worthwhile to go down is to start implementing a tag action per method available on the Twitter object, since that gets unnecessarily verbose in my opinion. So I started thinking about having some of the more common things you'd want to do with Twitter available via the tag for convenience, and maybe even let the login and action you want to perform be part of the same single tag. So maybe something like this:

<cftwitter action="setStatus" 
               screenname="foo" 
               password="bar" 
               status="Hello from OpenBD!" />

<cftwitter action="getFriendsTimeline" 
               screenname="foo" 
               password="bar" 
               variable="myTimeline" />
 

In other words, implement some of the commonly used actions so you can execute these in a single line, but leave the bulk of things available via first instantiating a Twitter object and then calling methods on that. My thinking is if you're going to perform multiple actions it's a lot less verbose to do that with the Twitter object than it is to call a tag each time and pass back in the variable name of the Twitter object on which you want to run the action.

So I'd love to get some opinions on this, and on the idea of a Twitter plugin in general, whether they be good, bad or indifferent.

Filed under  //  CFML   Java   OpenBD  

Comments (6)

Jan 1 / 8:25pm

New Query Functions Released in Open BlueDragon

New Query Functions released

Published: 2:01 PM GMT, Friday, 1 January 2010

We've justed finished the a whole new set of functions to help with the manipulation of Query objects and their respective datasources.

The following table highlights all the current functions within the Query category available in the OpenBD (nightly build) release:

DatasourceCreate Adds a new datasource to the system for use with any database functions. This does not persist over server restarts
DatasourceDelete Removes the given datasource. Note, it will not remove any datasource that was registered with the underlying bluedragon.xml file
DatasourceIsValid Checks to see if a given datasource has been previously registered using DataSourceCreate()
QueryAddColumn Adds a new column of data to the exist query object, returning the column number
QueryAddRow Adds the specified the number of rows to the end of the query
QueryColumnArray Returns all the data in a query for a given column
QueryColumnList Returns all the data in a query for a given row but as a structure
QueryDeleteColumn Deletes the column from the query, returning the deleted column data as an array
QueryDeleteRow Deletes the row within a query object. Modifies the original query object
QueryIsEmpty Determines if the query has any rows
QueryNew Creates a new query object with the columns past in of the optional types
QueryOfQueryRun Executes a Query-of-Query against a previous SQL result sets. Function version of CFQUERY
QueryRowStruct Returns all the data in a query for a given row but as a structure
QueryRun Executes the given SQL query against the given datasource, optionally passing in paramters. Function version of CFQUERY
QuerySetCell Sets the given column within a query with the value at the given row, or the last row if not specified
QuerySort Sorts the query based on the column specified and the order criteria given. Modifies the original query object
QuotedValueList Returns a quoted list of all the values, for a given column within the query, delimited by the value given
ToCsv Transforms the query object into a Comma Separated Value (CSV) block
ToHtml Transforms the query object into an HTML TABLE block
ValueList Returns a list of all the values, for a given column within the query, delimited by the value given

These functions will greatly increase the speed and efficiency to which you can work with Query objects.

Many of the functions where available using other means. For example, QueryDeleteColumn could have been achieved by performing a query-of-queries leaving out the column you wanted to remove. This however had a huge overhead, as well as duplicating the data.

You can read more about the DataSource functions over at Alan Williamson's blog.

Thanks to Peter J Farrell for many of his suggestions.

Comments (0)

Add Comment

Great new set of query functions released in the latest nightly of Open BlueDragon! Throw(), ThrowObject(), and GetException() have also been added. Great New Year's present!

Filed under  //  CFML   Open BlueDragon  

Comments (0)

Dec 30 / 5:24pm

Returning Java Exception Objects with Open BlueDragon

I'm working on a project that uses a pre-existing Java library to handle payment processing. This is great because it's a heck of a lot of stuff I don't have to write myself, but when payments fail I need to get a code that's contained in an exception object that's thrown in the Java code. This is a problem since given the way the Java code is written, the normal message and detail keys of the CFCATCH struct don't contain the code I need. To get the code I need to call a getCode() method on the Java exception object itself.

Open BlueDragon doesn't implement GetException() yet, which in theory lets you get the actual exception object thrown by Java (provided you specify the specific Java object type being thrown), but I figured since the Java class name is contained in the JAVAEXCEPTION key of the CFCATCH struct, it wouldn't be too hard to tell Open BlueDragon to put the actual Java object in that key instead of the class name.

It took a bit of hunting but it was extremely easy once I found the right spot. The CFCATCH struct is an instance of com.naryx.engine.cfCatchData (which extends cfStructData), and if a Java exception is thrown, the setJavaException() method in cfCatchData is called. This puts a new key called JAVAEXCEPTION in the CFCATCH struct and this key contains the name of the exception class thrown by Java.

Since I wanted to keep that key intact for the sake of compatibility, I decided to add another key called JAVAEXCEPTIONOBJECT to the CFCATCH struct, and this key contains the actual Java exception object. It was as simple as adding one line to the setJavaException() method. The original was this:

public void setJavaException(Throwable _value) {
ย ย ย  setData("javaexception", new cfStringData(_value.getClass().getName()));
}

So I changed it to this:

public void setJavaException(Throwable _value) {
 ย ย ย  setData("javaexception", new cfStringData(_value.getClass().getName()));
ย ย ย  setData("javaexceptionobject", new cfJavaObjectData(_value));
}

Now any Java errors that are caught by CFCATCH will contain the Java exception class, which lets me get at everything I need. This turned out to be a much more useful solution than going down the path of writing a Java class to wrap everything just so I could return what I needed from the Java exception object to OpenBD.

Yet another small example of the power of open source. If you want something to work differently, get in there and make it happen!

Filed under  //  CFML   Java   Open BlueDragon  

Comments (3)