The amazing adventures of Doug Hughes

Archive for October, 2007

Flex + Ant = No Flex Builder?

For those that have been working with Flex, or at least just reading some of the press, you will know that Adobe also puts out a very nice IDE called Flex Builder.  While Flex Builder gives you a lot of time saving features, it is not strictly necessary for deploying Flex applications.  It is possible to compile your Flex applications from the command line using the free compiler that is available for Flex.

In doing some digging for Ant related materials this afternoon, I came across a project called Flex2Ant which gives you the ability to "add a specific Ant task to the Ant installation that is part of the Eclipse IDE" and enable you to compile your Flex applications within Eclipse and without Flex Builder.

I have not tried this out yet as I like some of the other features of Flex Builder, but I thought it was another interesting use of Ant.

If you want to check it out, take a look at http://www.flex2ant.org/.

First Issue of My New FusionAuthority Column Online

The first installment of my new FusionAuthority monthly column is online. The column is called “Community Chronicles” and the goal is to write impactful and unique columns reflecting the state of the ColdFusion community from a different perspective than has been traditional in the ColdFusion community previously.
In the first installment, I include quotes from Bruce Chizen, CEO of Adobe, and Jonathan Wall, leader of the developer relations team. I had fun collecting my information and writing it, I hope you find it interesting and enjoyable to read!
Here’s the link: Community Chronicles 0.1: Now They’ve Really Done It

Ant + Subversion (on Windows)

In my continuing quest into all that is good with Ant, one of my tasks was to interface with our Subversion repository in order to export the latest code base, possibly tag it, al before shipping it off to the testing or production server.  In looking around, there are several ways to doing this – some that are limited to use within Eclipse, some that require third party downloads, and several others that were not documented well enough to know what they did.  In the end, I chose to use SVNAnt and configure things in a manner that I could run the build file from within Eclipse or from the command line if the need arose.

What is SVNAnt?

According to the documentation, SVNAnt "… is an ant task that provides an interface to Subversion revision control systems …"  Once SVNAnt is configured in your Ant build file, you can do almost anything via your build file that you could do using a Subversion client.  There are a few commands that are not supported, but there are 23 that are including the most common add, commit, export, etc. commands that you typically use.

You can download SVNAnt from http://subclipse.tigris.org/svnant.html.  The current release at this point is 1.0.0 which is available via a zip file.  In all of my incantations trying different things, I actually pulled the latest release from the SVN repository and compiled it to give me a 1.1.0 release.  This is the release I will be setting up below.

Setting it Up

  1. Download the latest release of SVNAnt from the SVN repository at: http://subclipse.tigris.org/svn/subclipse/trunk/svnant/
  2. Next, go to the folder in which you downloaded SVNAnt and copy the build.properties.example file to build.properties.  Uncomment all of the property lines and then add a single line at the bottom with the following text.

    targetJvm = 1.6

    In my case, I am running JVM 1.6.X with ColdFusion 8.  If you are running a lower JVM, adjust this number to match your JVM.  Then, save the file.

  3. Next, assuming you already have Ant installed (see http://www.alagad.com/go/blog-entry/better-development-practices-with-ant if not ), at the command line move to the folder where you downloaded SVNAnt above and type:

    ant makeDistrib

    You should get a bunch of stuff displayed with the last thing being a build successful message.   You should now have version 1.1.0 compiled and ready to go.

  4. Now, inside of your SVNAnt folder should be a folder called build, in which should reside a zip file named svnant-1.1.0.zip.  If you open up that zip file, in it should be a folder called lib, in which should be a collection of jar files.  These are the important ones that we need.  Extract / copy all of these files to the lib folder under your Ant installation.  In my case, I am using the Ant installation that comes as part of Eclipse, so I copied the files to:

    C:eclipsepluginsorg.apache.ant_1.7.0.v200706080842lib

With that complete, SVNAnt should be setup and we are ready to start writing build files.

A Test Build

I am not going to get into how to write a build file here, but lets at least create one that will test our SVNAnt installation.  Create a file called build.xml somewhere in your file system and put the following XML in it.

<project name="test" default="svn.test" basedir=".">
     <path id="svnant.classpath"  >
        <fileset dir=" [ PATH TO ANT LIB FOLDER WHERE SVNANT JAR FILES WERE PUT ] " >
            <include name="*.jar" />
        </fileset>
    </path>

    <typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.classpath" />

    <target name="svn.test">
        <svn>
            <wcVersion path=" [ PATH TO CHECKED OUT SVNANT WORKING COPY ] " />
        </svn>
        <echo message= "Subversion repository url: ${repository.url}" />
    </target>
</project>

Lets break this down to see what is happening here.  The path tag tells the build file where to find SVNAnt.  The only thing you will need to change here is the path to the Ant lib folder where you put the SVNAnt jar files.  Note: for windows, the path needs to contain forward double slashes, so "c:eclipse" would be "c:eclipse".

After the path tag, is the typedef tag.  The typedef tag defines the svn type so that we can use it later on.  Everything here should work as is with no changes.

Last we get to our target.  The target is the portion of the build file that will execute the various tasks you want.  In this case, we are doing a simple wcVersion SVN command to get some information about a subversion repository.  If you replace the contents of the path attribute with the file path to the working copy of the SVNAnt repository you checked out earlier, you should be able to run the build file.  Again, note for windows, the path needs to contain forward double slashes, so "c:eclipse" would be "c:eclipse".

Now, if you run this within Eclipse or run it from the command line, you should get back a nice little Build Successful message.  You now have the ability to perform Subversion operations from Ant and make your deployment process so much easier.

Learn More

To learn more about the commands that are available via SVNAnt, check out the documentation page for SVNAnt at http://subclipse.tigris.org/svnant/svn.html.

Announcing The First Enterprise ColdFusion With Model-Glue Training Session

Earlier this week I announced that Alagad would be offering training sessions on Model-Glue and several related technologies. Simply put, the feedback I received was tremendous. As a result, I’d like to announce that our first off-site training session will be held in Arlington, Virginia, just outside of Washington DC, from February 4th to 7th, 2008.

Program details can be seen here.

Details for the session can be seen here.

Registration has officially opened. Register early and get reduced pricing. Also, the first ten registrations before November 9th, 2007 will get free tickets to CF.Objective() 2008!

Validat 101 :: An Example

With In the previous articles in this series, we looked at all of the different concepts that went into developing Validat and making it as flexible as possible.  In this last article, I want to actually show how easy it is to implement Validat into a form validation scenario.  Validat could easily be used to validate business objects or in other data validation scenarios as well, but for now, we will just look at a form validation situation as I expect that will be the most common usage.

The Requirements

There are a few things that need setting up in order to get Validat working.

  • Validat Source – You can get the latest on Validat using your favorite Subversion client from http://svn.alagad.com/Validat/trunk.  As the project progresses, zip files will be made available via the project site for major releases.
  • ColdSpring Framework – Validat utilizes the factory design pattern and by default, the ColdSpring Framework.  The Bleeding Edge version of ColdSpring is required as there are several new features that have name make it into the main release yet.  ColdSpring can be found at http://www.coldspringframework.com.
  • ColdFusion Mappings – The following ColdFusion mappings are necessary and can be setup via the ColdFusion Administrator or your Application.cfc file if you are running ColdFusion 8.
    • /coldspring – Points to the root directory of the ColdSpring framework
    • /validat – Points to the src folder within the Validat distribution

With that out of the way, we are ready to build our example.

The Form

First off, we need a form to collect data to be validated.  There is nothing fancy here, just plain HTML.

<form action="submit.cfm" method="post" name="simpleForm1">
    <fieldset>
        <div class="formField">
            <label for="firstName">First Name:</label>
            <input type="text" name="firstName" id="firstName" class="inputText" />
            <div class="fieldMsg">required, less than 100 characters</div>
        </div>
        <div class="formField">
            <label for="middleName">Middle Name:</label>
            <input type="text" name="middleName" id="middleName" class="inputText" />
            <div class="fieldMsg">optional, less than 100 characters</div>
        </div>
        <div class="formField">
            <label for="lastName">Last Name:</label>
            <input type="text" name="lastName" id="lastName" class="inputText" />
            <div class="fieldMsg">required, less than 100 characters</div>
        </div>
        <div class="formField formButtons">
            <input type="submit" name="action" value="Submit" class="inputButton" />
            <input type="reset" value="Reset" class="inputButton" />
        </div>
    </fieldset>   
</form>

In this form, we have three text input fields … firstName, middleName, and lastName.  Now, in the submit.cfm script, we want to validate these fields and display any errors that might be found.

Validat Rules

Before we can validate the form data from our form, we need to tell Validat what data it is to be expecting and how to validate that data.  For this example, we will just use the configuration XML document mentioned on the first article in this series. 

To setup the configuration, we are going to create a file called validat.xml.  The name can be anything you want, this just makes it obvious as to what it is.

<validat>
 
    <!– validation rule definitions –>
    <validationRules>
       <rule name="length" validator="validateLength">
            <arg name="min" value="0" />
            <arg name="max" value="100" />
        </rule>
    </validationRules>
    <!– data set definitions –>
    <dataSets>
 
        <dataSet name="user">
 
            <dataElement name="firstName" required="true" message="errors.validation.user.firstName.required" >
                <assert rule="length" >
                    <!– optionally, additional arguments can be provided to the validator function –>
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.firstName.invalidLength" />
                </assert>
            </dataElement>
            <dataElement name="middleName" required="false" >
                <assert rule="length" >
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.middleName.invalidLength" />
                </assert>
            </dataElement>
            <dataElement name="lastName" required="true" message="errors.validation.user.lastName.required" >
                <assert rule="length" >
                    <arg name="min" value="1" />
                    <arg name="max" value="100" />
                    <message name="invalid" value="errors.validation.user.lastName.invalidLength" />
                </assert>
            </dataElement>
 
        </dataSet>
 
    </dataSets>
</validat>       

The first section of this file contains the validation rules that we will be using – in this case we will just be testing for fields within a specified length.   The second section of this file contains the data set definition, which we are calling the ‘user’ data set.   Within this data set definition, it shows there will be three data elements that are validated.   The data collection we pass to Validat might well have more than these three data elements, but these there are all that Validat will check. 

According to the data element definitions, both the firstName and lastName data elements are required and all three data elements must have a length between 1 and 100.  The data element definition for middle name looks a bit weird in that it is not required, but it must have a length between 1 and 100.  The way Validat works is that it will check the required state first and if the data value is not required AND it does not contain any data, it will skip the rest of the assertions.  If the data value is required OR it does contain data, then the assertions will be processed.

If you want to read more about this configuration file and its layout, check out the first article in this series.

The ColdSpring Configuration

Quickly before we get to the form script, we need to let ColdSpring know how to instantiate the Validat service object when we request it.   In your ColdSpring.xml file – or you can just create a new one in the same folder if you don’t have one already – insert the following XML snippet.

<beans>
    <import resource="/validat/config/validat.xml" />
    <bean id="validat" class="validat.validat" >
        <constructor-arg name="factory">
            <ref bean="csFactory" />
        </constructor-arg>
        <constructor-arg name="pathToConfigXML">
            <value>validat.xml</value>
        </constructor-arg>
    </bean>
</beans>

The first import tag is what requires the bleeding edge version of ColdSpring as it imports the default ColdSpring configuration for Validat.  This default configuration sets up all of the validators and data transformers that come with the Validat distribution.

The Validat bean element sets the dot notation class path to the Validat service object and passes a couple of arguments to its constructor.  The first is a pointer to the ColdSpring bean factory itself as Validat uses a bean factory to create instances of the validators and data transformers as needed.  By changing this argument value, you could easily put another bean factory implementation in place of ColdSpring if you desired.  The second argument is the path to the Validat XML configuration file we created above.  At this point, it is assumed everything is in the same folder, so a relative path is used.

The Form Submit Script

Now that Validat is configured and knows to validate the data in the form, we just need to set it loose.  Our original form submitted to a file called submit.cfm, so that is the next and last file we will need to create.

First off, the tough part – validating the data.

<!— initialize the ColdSpring bean factory —>
<cfset csFactory = createObject("component", "coldspring.beans.DefaultXmlBeanFactory").init() />
<cfset csFactory.loadBeansFromXmlFile(expandPath("../_common/coldspring.xml"), true) />
 
<!— get an instance of the Validat validation engine —>
<cfset formValidator = csFactory.getBean(‘validat’) />
 
<!— validate the form and collect any errors —>
<cfset errorCollection = formValidator.validate(‘user’, form) />

But that is only 4 lines of code !!! 

Yep, that is all Validat needs and the first two are just setting up the ColdSpring bean factory instance.  The third line of code uses the ColdSpring bean factory to get an instance of Validat and then all of the work is done in the forth line of code.  To validate a collection of data, we simply pass the name of the data set that we are validating the data against, along with the collection of data being validated to the validate method and in return, we get a collection of errors that were found.  That’s it!

The Error Collection

The error collection is an object that comes with Validat and is simply a container for the validation errors found by Validat.  In has a very simple API that allows you to quickly check if it contains errors and to retrieve those errors.

In the above example, to display a message if errors were found would require the following code snippet:

<cfif errorCollection.hasErrors() >
    One or more errors were found in the data you submitted.
</cfif>

To retrieve the list of errors for a given form field and convert them into a list of errors to be displayed, you would use the following code snippet;

<cfif arrayLen(errorCollection.getErrorsByDataElement(‘firstName’)) GT 0 >
    <cfset arrErrors = errorCollection.getErrorsByDataElement(‘firstName’) />
    <cfset fieldErrors = "" />
    <cfloop from="1" to="#arrayLen(arrErrors)#" index="errorPtr">
        <cfset listAppend( fieldErrors, arrErrors[errorPtr].message, ‘<br/>’ ) />
    </cfloop>
<cfelse>
    <cfset fieldErrors = "" />
</cfif>

And with that, you have a complete form validation solution.

Wrap Up

This article wraps up the Validat 101 series.  If you want to find more information about Validat or try it our for yourself, check out the following sites.

Validat 101 :: Transformers

The last piece of the puzzle for Validat is a concept called Data Transformers.  When we were researching the requirements for Validat, I made several blog postings trying to determine how people handled validation.  One of the things that came out of those postings was that the data being validated was not always in a structure such as the form scope.  Some people liked to take data and stuff it into a bean or business object and then validate the object while others prefer to validate the data before they use it.  Then, there is always the unknown edge case and the goal was really to make Validat work in any situation where you needed data validation.  The answer we came up with to this question is what we call Data Transformers.

What is a Data Transformer?

A data transformer simply transforms data – novel huh?  The Validat data validation engine validates data in a key / value structured format.  So, if you are validating data in the form structure, the data transformer does little more than make a copy of the form structure and pass it to the validation engine.  However, if you are validating data in a business object, the data transformer extracts the data from that business object, stores it in a structure and passes that structure to the validation engine.

Adhering to the concept of abstraction, a data transform is implemented as a simple ColdFusion component that follows a prescribed interface.  Not wanting to limit the use of Validat to ColdFusion 8, we chose to create a single component called transformer.cfc, which all data transformer components extend.

So, when it comes time to validate data that is in a different format, it is simply a matter of creating a new transformer component that follows the prescribed interface, registering that component, and you are off and validating.

The Interface

Within each transformer component are two functions – an init constructor and a function called getData.  It is possible for other functions to be added to support the data retrieval process, but these two functions are all that is required by the API.  If you open up any of the transformer objects that come with Validat, you will notice that the init function does not do much in most cases – the bulk of the work is handled in the getData function.

Deconstructing a Transformer

As mentioned before, the structure transformer does not do much, so lets walk through the bean transformer to see how it works..  The following code is contained in the transformBean.cfc component (comments have been stripped).

<cfcomponent
    displayname="transformBean"
    output="false"
    hint="ColdFusion bean data transformer."
    extends="transformer">
 
    <!— ———————————————————— —>
    <!— constructor —>
 
    <cffunction name="init" access="public" returntype="transformBean"
        hint="The default constructor for the transformer object, returning the initialized transformer object instance">
 
        <!— call the base constructor —>
        <cfset super.init() />
        <!— return the initialized transformer object —>
        <cfreturn this />   
    </cffunction> <!— end: init() —>
    <!— ———————————————————— —>
    <!— public methods —>
 
    <!—
        function: getData
        description:    Retrieves the data values in the form of key / value pairs from the bean object.
    —>
    <cffunction name="getData" access="public" output="false" returntype="struct"
        hint="Retrieves the data values in the form of key / value pairs from the bean object.">
 
        <cfargument name="dataCollection" type="any" required="true" hint="The data collection to be transformed" />
        <!— setup temporary variables —>
        <cfset var beanMetaData = getMetaData(arguments.dataCollection) />
        <cfset var resultStruct = structNew() />
        <cfset var funcPtr = 0 />
        <!— loop over the meta data functions, looking for getters —>
        <cfloop from="1" to="#arrayLen(beanMetaData.functions)#" index="funcPtr">
            <!— if the function appears to be a getter —>
            <cfif left( beanMetaData.functions[funcPtr].name, 3 ) EQ "get" >
                <!— call the getter function and insert the value into the result structure —>
                <cfset structInsert( resultStruct, beanMetaData.functions[funcPtr].name, evaluate( "arguments.dataCollection.#beanMetaData.functions[funcPtr].name#" ), true ) />
            </cfif> <!— end: if the function appears to be a getter —>
        </cfloop> <!— end: loop over the meta data functions, looking for getters —>
        <!— return the result structure —>
        <cfreturn resultStruct />
    </cffunction> <!— end: getData() —>
 
</cfcomponent>

In the <cfcomponent tag, the only thing to take notice of is the fact that we are extending the base transformer.cfc component which is located in the same transformers folder as the bean transformer.

The first method shown here is the init constructor which is public and returns the current transformBean object instance after any confirmation has been completed.  In this example, the only operation this function performs is a call to super.init() which calls the init function on the extended transformer object.

The real work of any transformer object is in the getData function.  The getData function takes as an argument a data collection of any type and returns a structure of key / value pairs extracted from the data collection.  In this case, the data collection represents a business object from which the transformer will be extracting data.

The way the bean transformer works is that it gets the meta data for the business object and from that meta data, extracts any functions that begin with the word ‘get’.  If the business object was build using "standard" development practices, there should be getter and setter methods for every data element in the bean.  Therefore, the transformer finds all of the getters and then one by one, calls each getter and inserts the returned value into a structure.

The transformer now has a structure of key / value pairs that can be returned to the Validat data validation engine for validation.

The Big Picture

Like validator objects, data transformer objects require registering.  After creating a new data transformer object, the first thing that needs to happen is that the transformer object should be registered with the Validat ColdSpring XML configuration file (/scr/config/validat.xml).  In this configuration file, there is a section for transformers and the included transformer objects are setup here.  To add a new transformer object, just add a new line like below to the validat.xml file.

<bean id="transformBean" class="validat.dataTransformers.transformBean" />

The bean id value must be unique, but can be anything of your choosing.  The class value is the dot notation path to your transformer cfc.  Remember your bean id as you will need it in the next part.

Once the transformer is registered with the ColdSpring bean factory, it must be connected to one or more data sets in order to be utilized.  The data definition contains all of the data sets, which if a transformer is not specified, will utilize the basic form structure transformer.  A data set definition with a transformer specified looks like this.

<data-set name="user" transformer="transformBean">

When validate function for Validat is called, it accepts two arguments – a data collection and a data set name to validate that data collection against.  The first thing Validat does is look at the data definition for the specified data set name to determine which data transformer it needs to use to extract the data from the data collection.  In the above case, the transformer attribute of the data-set element indicates that when this data set is validated, Validat should utilize the transformer object with bean id ‘transformBean’ to extract the data from the data collection.  Once the data is extracted, Validat moves on with the validation process for all of the data elements contained in the data set.

Wrap Up

Data Transformers and Validators are what make the Validat data validation engine so powerful and give it the ability to be dropped into virtually any scenario.  If you have a custom situation where you need validation, it is a very quick an easy process to write a data transformer that fits your requirements and to drop it into Validat.  Then you have instant data validation.

In the next part of this series, we will setup a working example where we use Validat to validate the data coming from a form and show exactly how it all works together.  In the mean time, check out the Validat project page (http://trac.alagad.com/Validat) and join the Validat mailing list (http://groups.google.com/group/Validat).  Until then ….

Alagad To Invade Scotland

This was actually announced previously by Andy Allan, but both Scott Stroz and myself will be representing Alagad at Scotch on the Rocks 2008.

For those who are not already aware, Scotch on the Rocks is a premiere ColdFusion conference in Europe. It’s held in Edinburgh, Scotland and, from what I’ve been told about past events, is simply fantastic.

Personally, I’m excited just to be going to Scotland. However, it’s an honor to have been invited and to have Scott invited too.

I don’t want to promise too much, but some other Alagadians may just be attending too.

See you there!

Server Virtualization – The Coming Wave

Many of us have tried ways to run multiple operating systems on a single physical computer. Probably the most notable product in this areahas beenVMWare . Microsoft is catching on withits ownVirtual PC offering and of course there is Parallels which came out of the Apple world.

One thing about virtualization that is not widely known is that it is an old principle (in computer time terms). It was actually used in the days when mainframes were the only game in town for high end computing needs.

One problem that was often encountered when running multiple operating systems on the same physical computer is that of performance. There was always a significant degradation which largely speaking ruled out any chance of using virtualization in a production server setting. I first noticed changes in this whilst with a client in Arizona back in 2005. They had built a very flexible lab-QA-Test environment using VMWare. This interested me because they were able to load-test code fairly aggressively and get reasonable performance even though it was running in a virtual environment, that got me thinking.

Recently, I attended a conference in San Antonio Texas and there was a presentation by a company called Xensource. Xensource seem to be taking virtualization to a new level and I think I am right in saying the company came out of an open-source initiative called “xen”.Xensource were recently acquired by Citrix and I think this in indicative of another trend centered around creating distributable complete environmentswith runnable applications. This is addressed to a certain extent by this section from the Xensource web site.

  • Portability: The use of abstract devices within virtual machines, combined with the encapsulation of virtual data in file-backed or volume-backed virtual disks, makes it easy to move virtual machines from one physical system to another, for maintenance, more effective resource utilization, or simply for replicated provisioning.In many cases, running virtual machines can even be moved while they are online, with no interruption to service.

We will be doing more work here at Alagad around the whole topic of virtualization.The next steps will be to take one of our Windows 2003 lab servers and install Xensource on there and then follow that by attempting to install different operating systems and hopefully ColdFusion. I will be blogging about that in the near future as we move through each stage.

It seems to us that virtualized servers will play a large part in the continuing evolution of computing. I wonder how many servers sitting in data centers and dedicated to a specific task are under utilized ?

Validat 101 :: Validators

Data validation in its most simplest terms is applying one or more validation rules to a piece of data.  A validation rule might be as simple as making sure a value exists for a required field, it it could more complicated by taking multiple data values and testing them together for certain criteria.  Each different application has different data that needs validating and different validation rules of varying complexity that need to be tested.  So, in the development of Validat, we chose to create what are call Validators.

What is a Validator?

A validator is a single validation rule which when provided with one or more data values, validates those data values and returns true if the validation passes or returns an error message if the validation fails.

A validator is implemented a simple ColdFusion component that follows a prescribed interface.  We did not want to limit the use of Validat to ColdFusion 8, so we did not implement interfaces.  Instead, there is a single component called validator.cfc that all validator components extend.

The Interface

Within each validator component are two methods – a init constructor and a single method called validate.  It is possible that other methods could be added to support the validation process, but these two methods are required by the API.  If you open up any of the validators that come with Validat, the init function does not do much in most cases.  The validate function is where the real work is done.

Deconstructing a Validator

Lets take one of the validators that comes with Validat – the alpha validator and break it down to see how it works.  The following code is contained in the validateAlpha.cfc component (comments have been stripped).

<cfcomponent
    displayname="validateAlpha"
    output="false"
    hint="Alphabetic string validation rule."
    extends="validator">
    <!— ———————————————————— —>
    <!— constructor —>
 
    <cffunction name="init" access="public" returntype="validateAlpha"
        hint="The default constructor for the validator rule, returning the initialized validator rule instance">
 
        <!— call the base constructor —>
        <cfset super.init() />
        <!— return the initialized validatoin rule —>
        <cfreturn this />   
    </cffunction> <!— end: init() —>
    <!— ———————————————————— —>
    <!— public methods —>
 
    <!—
        function:         validate
        description:    Check to see if the data value contains only alpha characters ( A-Z, a-z ).
    —>
    <cffunction name="validate" access="public" output="false" returntype="string"
        hint="Check to see if the data value contains only alpha characters ( A-Z, a-z ).">
 
        <cfargument name="data" type="any" required="true" hint="The data to be validated" />
        <cfargument name="args" type="struct" required="false" default="#structNew()#" hint="The addtional arguments necessary to validate the data" />
        <cfargument name="dependencies" type="struct" required="false" default="#structNew()#" hint="The additional dependencies necessary to validate the data" />
        <!— check to see if the data value represents a simple string value —>
        <cfif NOT isSimpleValue( arguments.data ) >
            <cfthrow type="validat.invalidData" message="validat: The validation rule ‘validateAlpha’ only accepts simple data types." />
        </cfif>
        <!— check to see if the data value contains only alpha characters ( A-Z, a-z ). —>
        <cfif NOT reFind(‘[^A-Za-z]’, arguments.data) >
            <cfreturn true />
        </cfif>
 
        <cfreturn "invalid" />
    </cffunction> <!— end: validate() —>
 
</cfcomponent>

In the <cfcomponent tag, the only thing to really take notice of is the fact that as mentioned before, this component extends the validator object.

The first method of the validator is the init constructor which is public and returns the current validateAlpha object instance after any configuration has been done.  In this simple example, the init method calls super.init() which means that it calls the init method on the extended validator object.  Then, it just returns the current object.

The second method of the validator is the validate method which performs the real validation work.  The interface for this method states that it accepts the data value to be validated, an optional structure of arguments necessary to validate the data, and an optional structure of dependencies necessary to validate the data.  The data value is fairly self explanatory, but lets look at the other two arguments.

The arguments structure contains one or more key value pairs for various arguments used in the validation process.  An argument might include something like a minimum or maximum value or a list of values to check against.  In the case of this validator, no arguments are provided.

The dependencies structure contains one or more key value pairs for various dependencies used in the validation process.  A dependency is another data value (data element) that is used with the current data value in the validation process.  For example, in testing to see if a state is valid, you would also be dependent upon the country specified as well.

The body of the validate method contains the various checks upon the data value and based upon those checks returns either true or in this case ‘invalid’.  The body of this method could include calls to other methods, calls to other objects such as a data access object, etc.

The Big Picture

If you have followed the first two parts of this series, then you have already seen a couple of references to validators.  If you create a new validator, the first thing you need to do is register it with the Validat ColdSpring XML configuration file (/src/config/validat.xml).  In this configuration file is a section for validators and all of the included validator objects are setup here.  To add a new validator object, just add a new line like below to the validat.xml file.

<bean id="validateAlpha" class="validat.validationRules.validateAlpha" />

The bean id value must be unique, but can be anything of your choosing.  The class value is the dot notation path to your validator cfc.  Remember your bean id as you will need it in the next part.

The second place your validator must be registered is in the data definition that was discussed in the previous part of this series.  The data definition contains mappings for all of the validation rules that can be applied to data elements.  This mapping looks something like this.

<validationRules>
 
    <rule name="alpha" validator="validateAlpha" />
 
</validationRules>

The rule element specifies a name for the validator and the validator attribute contains the bean id you created in the ColdSpring XML file.  Your validator is now registered and ready to use.

When the Validat data validation engine is processing the data definition upon validation, every time it comes to an assertion element, it takes rule name for that assertion element, matches it to a validation rule, then uses ColdSpring to retrieve an instance of the corresponding validator cfc.  It then calls the validate method on that cfc, passing in the current data value and any arguments or dependencies.  After getting the result from the validate method, it moves on to the next assertion and the next data element until the entire data set has been processed.

Wrap Up

Validators are just one example of how flexible and customizable the Validat data engine can be.  In the next part of this series, we will take a look at Data Transformers which allow Validat to validate any type of data – whether it be a collection of form data, a bean object, or anything else you can come up with.  Until then ….

Validat 101 :: Data Definitions :: Part 2

In part one of this article, we looked at the data definition xml configuration option for the Validat data validation engine. In some cases, hard coding the data definitions is not the ideal choice. For example, your system might allow for dynamically build forms and you might want to dynamically assign validation rules to the form fields. One of the core concepts behind the Validat data validation engine is flexibility and the ability to fit into any scenario. To address this issue, Validat offers a complete API for creating and managing the data definition in addition to using the configuration XML.

Overview

The Validat API is designed with a series of functions for creating, updating, deleting, or listing validation rule mappings, data sets, data elements, and assertions. You can use the API to perform actions on an existing data set that was created via the configuration XML file discussed in part one, or you can start from scratch.

Lets break down the different capabilities available through the API.

Validation Rules

In the context of the data definition, validation rules are a mapping between the actual validation rule object and a rule name that can be referenced for each data element. As will become obvious as we progress through the API, there are a standard set of functions for managing validation rules as well as the other elements of the Validat data definition.

addRule(ruleName, validator, ruleArgs, ruleMsgs)

As the name suggests, this method simply adds a new validation rule to the data definition. It accepts all of the attributes of a validation rule – name, validator, arguments, and messages – and overwrites any existing validation rules with the same name.

addRuleXML(ruleXML)

This method adds a new rule, but does so via an XML snippet. This function is actually used when parsing the XML data definition, but can also be used directly, passing just the XML snipped for a validation rule.

getAllRules()

This method returns a structure, keyed by the validation rule name, with all validation rules in the data definition.

getRule(ruleName)

This method returns a structure, keyed by the validation rule attribute, with all of the data regarding the validation rule with the specified rule name.

remRule(ruleName)

This method removes a validation rule, based upon its rule name, from the data definition.

ruleExists(ruleName)

This method simply tests to see if a validation rule is defined in the data definition with the specified rule name.

Data Sets

As mentioned in the first part of this article, data sets are simply collections of data elements later to be connected with a given form, bean, or other collection of data to be validated. The following API functions are available for manipulating data sets programmatically.

addDataSet(dataSetName, transformer, overwrite)

This method simply adds a new data set to the data definition. It accepts all of the attributes of a data set – name and transformer – along with an optional overwrite argument. With data sets, the developer can decide not to overwrite an existing data set with the same name.

addDataSetXML(dataSetXML, overwrite)

This method adds a new data set, but does so via an XML snippet. This function is used when parsing the XML data definition, but can also be used directly, passing just the XML snipped for a data set. Additional, it also accepts an optional overwrite argument allowing the developer to decide not to overwrite an existing data set with the same name.

getAllDataSets()

This method returns a structure, keyed by the data set name, with all data sets in the data definition.

getDataSet(dataSetName)

This method returns a structure, keyed by the data set attribute, with all of the data regarding the data set with the specified data set name.

remDataSet(dataSetName)

This method removes a data set, based upon its data set name, from the data definition.

dataSetExists(dataSetName)

This method simply tests to see if a data set is defined in the data definition with the specified data set name.

Data Elements

Data elements represent individual pieces of data that are to be validated. Data elements may have one or more validation rules applied and are grouped together into data sets. The following API functions are available for manipulating data elements programmatically.

addDataElement(dataSetName, dataElementName, dataSetConnectionName, required, message, overwrite)

This method simply adds a new data element to the data definition. It accepts all of the attributes of a data element – parent data set name, data element name, required, message, and overwrite. With data elements, the developer can decide not to overwrite an existing data set with the same name. The dataSetConnectionName argument is optional and allows for chaining data sets and data elements. For example, if you were validating a person bean object, that person bean might have a property called homeAddress which was a pointer to an address bean object. By using this data set / element chaining, you can have a data element called address which actually points to an entire other data set containing all of the data elements that make up an address.

addDataElementXML(dataSetName, dataElementXML, overwrite)

This method adds a new data element to the specified data set, but does so via an XML snippet. This function is used when parsing the XML data definition, but can also be used directly, passing just the XML snipped for a data element. Additional, it also accepts an optional overwrite argument allowing the developer to decide not to overwrite an existing data element with the same name.

getAllDataElements(dataSetName)

This method returns a structure, keyed by the data element name, with all data elements in the specified data set.

getDataElement(dataSetName, dataElementName)

This method returns a structure, keyed by the data element attribute, with all of the data regarding the data element with the specified data element name in the specified data set.

remDataElement(dataSetName, dataElementName)

This method removes a data element, based upon its data set and data element name, from the data definition.

dataElementExists(dataSetName, dataElementName)

This method simply tests to see if a data element is defined in the specified data set with the specified data element name.

Data Assertion

Data assertions represent the link between a data element and a validation rule – in other words asserting that the validation rule evaluate to true for the data element. Data assertions may also apply at the data set level if they test multiple data elements. The following API functions are available for manipulating data assertions programmatically.

addAssert(dataSetName, dataElementName, rule, continueOnFail, args, dependencies, messages)

This method simply adds a new data assertion to the data definition. It accepts all of the attributes of a data assertion – applicable data set name, applicable data element name (optional), validation rule name, continue on fail, and optional collections of arguments, dependencies, and error messages. If an data set level assertion exists with the same name, it will not be overwritten – data set level assertions must be removed manually. If a data element level assertion exists with the same name, it will be overwritten.

The dependencies collection is for data set level assertions and maps one or more data elements to this assertion. For example, you have the need to test if a user account already exists in the system, but that test involves the user’s first name, last name, and email address. A single data assertion could be written with dependencies on all three of these data elements, in which case the value of all three data elements would be passed to the associated validation rule.

addAssertXML(dataSetName, dataElementName, assertXML)

This method adds a new data assertion to the specified data set and/or data element, but does so via an XML snippet. This function is used when parsing the XML data definition, but can also be used directly, passing just the XML snipped for a data assertion. If the data element name is specified, it is assumed the assertion is being added directly to that data element. If not, the assertion will be added at the data set level.

getAllAsserts(dataSetName, dataElementName)

This method returns an array containing all of the data assertions in the specified data set and/or data element.

getAssert(dataSetName, dataElementName, assertId)

This method returns a structure, keyed by the data assertion attribute, with all of the data regarding the data assertion with the specified assertion id in the specified data set and/or data element.

remAssert(dataSetName, dataElementName, assertId)

This method removes a data assertion, based upon its assertion id and the specified data set and/or data element from the data definition.

Additional Information

More information on Validat will be available on the Validat project site at http://trac.alagad.com/Validat as Validat gets closer to its first beta release. In the mean time, check out the Google groups site (http://groups.google.com/group/Validat) to ask any questions.

In the next set of Validat 101 topics, we will take a closer look at the validation rule and transformer objects that help make Validat so extensible. Until then …..

Tag Cloud