Apache Ant Best Practices

Before Ant, building and deploying web applications required a series of scripts or manual processes, which often led to mistakes.

Apache Ant is a software tool for automating software build processes. It is similar to Make but is implemented using the Java language, requires the Java platform, and is best suited to building Java projects. However, that doesn’t mean it is restricted to Java projects. I use Ant increasingly for all my web development projects as it is an integral part of Eclipse, my IDE of choice. It makes building applications and releasing them across different servers far more efficient and less problematic.

When I start a new project, after creating the folder structure, I create the Ant build file. Ant defines the build process and must be used by every developer working on the project. All of the tips in this article assume that the Ant build file is extremely important, must be written with care, and maintained in version control and re-factored periodically, when the project dependencies change.

Ant uses XML to describe the build process and its dependencies. By default the XML file is named build.xml. This makes it really simple for you setup and edit different build processes. However, since Ant is relatively simple to set up, you need to follow a common set of best practices. Some of these best practices were inspired by mistakes made on previous projects, or ideas passed on to me by other developers.

Automate absolutely everything

Ant is a powerful tool. If you choose to use it, get it to do absolutely everything. Ant can integrate with your source control databases such as Subversion (SVN), run SQL scripts, change file permissions, send files across FTP, zip and un-zip files, and many more tasks besides these.

If you use Ant, only use Ant

Use Ant as a common baseline. Regardless of what IDE you use to develop your applications, set up an Ant build file that all team members use. The build.xml file is the one true build script. Make a rule that everyone should perform a successful Ant build before code is checked into version control. This will ensure that code will always build from the same build file.

Follow consistent conventions

Ant expects your build file to be called build.xml and the build’s properties file build.properties. These files should also be in the root directory of your project. Other than an insane desire to change convention and confuse other team members, don’t change this convention. Another less-well-known convention is to prefix all internal commands with a hyphen (-). It has the advantage that it is not possible to invoke targets that follow this naming convention, from the command line.

Spend time formatting the build file. Since XML is quite verbose, use tabs and line breaks to make the file readable to the human eye. Ant itself doesn’t care if the file looks pretty, but you can bet that you and your team will.

Pick meaningful, human-readable names for targets and properties. For example dir.reports is better than simple rpt. The specific naming convention is not important, beyond being meaningful to your organisation. For example, I use the following:

deploy.local
deploy.dev
deploy.test
deploy.live
-build
-clean
-concatenate
-minify
-prepare

The -concatenate and -minify commands are specific to web projects, the later using the Yahoo compressor library to minify CSS and JavaScript files.

Provide a clean target

Every build file should include a target that removes all generated files and directories, bringing everything back to its original pristine state. All files remaining after the clean should be those found in version control.

An example clean command could be as follows:

<target name="clean" description="Deletes all generated files and directories">
	<delete dir="${dir.build}" />
	<delete dir="${dir.dist}" />
</target>

Use build files for all stages of the development process (development, staging and production)

Ant standardises your build and release cycle. Therefore use it for all stages of the development process. Use it for releasing code to your local development server, your staging or user acceptance testing server and your production server. The different deployments can obviously differ slightly based upon the needs, i.e. your production build need not include the creation of dummy data, but may include a call to source control.

Make build files self-contained

A build file that relies on external dependencies is one that will be difficult to configure or has the potential to cause problems. If your build depends on additional tools, put them in your source control repository. I generally include a lib for all dependencies in my project root. This folder includes such files as the Yahoo Compressor or JSLint.

Prefer a single build file

It is possible to split the build up into several small build files, each of which is responsible for a small proportion of the overall build. This isn’t always the best idea! Breaking the build often makes it harder to comprehend the whole process. It is better not to over-engineer the project and keep to a single, well formatted build file.

If your project is split into different build files, there should always be a master build file, found in the root directory of the project, even if it only delegates actual work to subordinate builds.

Put the build.xml file in the project’s root directory

The Ant build file can reside anywhere in the project tree, but conceptually it makes sense to put the file in the project root. This keeps things clean, simple and somewhat obvious to new members to the project. Having a build file in the top-level directory also makes it conceptually easy to see how relative paths point to different directories in the project tree.

When the build.xml file is in the top-level directory, you can compile code from the command line without the need to change the working directory.

Modularise your project

Arrange your project into coherent self-contain modules.

The following shows how I typically arrange my project files.

[root directory]
	/docs
	/lib
	/src
build.properties
build.xml
task.properties

The docs folder contains project documentation, the lib folder contains libraries specific to the project and required by Ant (generally this is a link to repository containing a number of utility JAR files, such as those for SVN and FTP). Finally, the src folder contains the actual project files.

Use version control

It is important to use version control for your entire project. The build file is an important artefact that needs to be versioned along with the source code of the project. When you tag a build for release, the build file should also be included. If you then need to roll back to a previous release, you will be able to build the code based upon the build file used for that particular release (after all, build files develop along with changes to the source code).

Third-party JAR and executable files should also be maintained in your local version control. This makes it possible to recreate previous releases, after all third-party libraries are likely to develop and change as frequently as your own code. If you want or need to take advantage of these changes, it is necessary to version control the older versions.

Avoid including build output in version control. Provided that you use version control correctly, you will be able to recreate these files at a later date.

Include comments in the build file (self-documenting)

Make the build file self-documenting. Adding target descriptions is one way to achieve this. For example:

<target name="clean" description="Deletes all generated files and directories">

Internal targets should not include description attributes. Internal targets may include targets that perform immediate processing, such as file concatenation or minifying.

Another way to include help in the build file is the echo tag. You can put any amount of comment between these tags and the information is printed to screen. For example:

<target name="clean" description="Deletes all generated files and directories">
	<echo>Cleaning project...</echo>
	<echo>Deleting build directory...</echo>
	<delete dir="${dir.build}" />
	<echo>Deleting dist directory...</echo>
	<delete dir="${dir.dist}" />
</target>

Summary

By using Ant and creating and maintaining build scripts for a project, the reliance on ad-hoc manual procedures for compiling and creating websites is removed. Using a defined process with Ant, or similar build tool, removes errors across the entire project, whilst allowing teams to develop code more efficiently.

References

Holzner, Steve (2005). Ant: The Definitive Guide, 2nd Edition, O’Reilly, ISBN 978-0-596-00609-9.

Apache Ant – http://ant.apache.org

Take control of your code with these programming best practices from Kevlin Henney. At JAOO Aarhus 2008 Kevlin used a trash can, vampires, a train wreck, whiskey and much more to make you understand and remember his 13 constructive points (a programmer’s dozen) about programming and code smells.

The 13 points made by Kevlin were:

  • 0. Prefer code to comments.
  • 1. Follow a consistent form.
  • 2. Employ the contract metaphor.
  • 3. Express independent ideas independently.
  • 4. Encapsulate.
  • 5. Parameterize from above.
  • 6. Restrict mutability of state.
  • 7. Favor symmetry over asymmetry.
  • 8. Sharpen fuzzy logic.
  • 9. Go with the flow.
  • 10. Let code decide.
  • 11. Omit needless code.
  • 12. Unify duplicate code.

You can see a video of Kevlin’s presentation on the JAOO website.

PCI DSS stands for Payment Card Industry Data Security Standard, and is a worldwide security standard assembled by the Payment Card Industry Security Standards Council (PCI SSC). The PCI security standards are technical and operational requirements that were created to help organizations that process card payments prevent credit card fraud, hacking and various other security vulnerabilities and threats. The standards apply to all organizations that store, process or transmit cardholder data – with guidance for software developers and manufacturers of applications and devices used in those transactions. A company processing, storing, or transmitting cardholder data must be PCI DSS compliant.

Types of Data on a Payment Card

The PCI SSC (Council) is responsible for managing the security standards, while compliance with the PCI set of standards is enforced by the founding members of the Council: American Express, Discover Financial Services, JCB International, MasterCard Worldwide and Visa Inc. Non-compliant companies who maintain a relationship with one or more of the card brands, either directly or through an acquirer risk losing their ability to process credit card payments and being audited and/or fined.

All in-scope companies must validate their compliance annually. This validation can be conducted by Qualified Security Assessors, i.e. companies that have completed a three-step certification process by the PCI SSC which recognises them as being qualified to assess compliance to the PCI DSS standard. However, smaller companies have the option to use a Self-Assessment Questionnaire. Whether this questionnaire needs to be validated by a QSA depends on the requirements of the card brands in that merchant’s region.

The current version of the standard specifies 12 requirements for compliance, organised into 6 logically related groups, which are called “control objectives.”

  1. Build and Maintain a Secure Network
    • Requirement 1: Install and maintain a firewall configuration to protect cardholder data
    • Requirement 2: Do not use vendor-supplied defaults for system passwords and other security parameters
  2. Protect Cardholder Data
    • Requirement 3: Protect stored cardholder data
    • Requirement 4: Encrypt transmission of cardholder data across open, public networks
  3. Maintain a Vulnerability Management Program
    • Requirement 5: Use and regularly update anti-virus software
    • Requirement 6: Develop and maintain secure systems and applications
  4. Implement Strong Access Control Measures
    • Requirement 7: Restrict access to cardholder data by business need-to-know
    • Requirement 8: Assign a unique ID to each person with computer access
    • Requirement 9: Restrict physical access to cardholder data
  5. Regularly Monitor and Test Networks
    • Requirement 10: Track and monitor all access to network resources and cardholder data
    • Requirement 11: Regularly test security systems and processes
  6. Maintain an Information Security Policy
    • Requirement 12: Maintain a policy that addresses information security

Compliance with these requirements can be summarized into 3 main stages:

  • Collecting and storing: Secure collection and tamper-proof storage of all log data so that it is available for analysis.
  • Reporting: Being able to prove compliance on the spot if audited and present evidence that controls are in place for protecting data.
  • Monitoring and alerting: Have systems in place such as auto-alerting, to help administrators constantly monitor access and usage of data. Administrators are warned of problems immediately and can rapidly address them. These systems should also extend to the log data itself –- there must be proof that log data is being collected and stored.

What does this actually mean for web application developers?

It is considerably more expensive and more time-consuming to recover from a security incident than to take preventative measures ahead of time. If you follow the guidelines below, you will go along way to securing you application in line with the PCI DSS regulations. Many of the measures apply to general application security, but since PCI DSS is all about security, they are worth mentioning.

Server-level Security:

  • Separate web- and database-servers on to different physical machines.
  • Secure the web- and database-servers with traditional techniques. Only authorised accounts should have the capabilities to run tasks on the machine. That means not giving admin-rights to the user account.
  • Keep servers up-to-date with the latest patches and software releases.
  • Minimise the number of services running on the server. This means limiting the services to only those required for the web- or database-servers to function.
  • Secure information in transit between servers. This may mean physically securing the network to prevent evesdropping via encryption or obfuscating the data amongst innocuous ‘noise’.
  • Secure the database server behind a firewall.

Application-level Security:

  • Separate ColdFusion, the webserver and database server user accounts. They should never be under the same system account.
  • Create a database user specifically for your ColdFusion datasource and restrict it to only the activities required for the application. The user should not have database-owner rights, access to databases not relating to the application or access to the system tables.
  • Revoke privileges in the ColdFusion datasource definition to prevent the SQL commands CREATE, DROP, GRANT, REVOKE and ALTER.
  • General settings in the ColdFusion Administrator:
    • Check the Disable access to internal ColdFusion Java components option.
    • Check the Enable Global Script Protection option.
    • Add a Missing Template Handler.
    • Add a Site-wide Error Handler.
    • Reduce the Maximum size of post data from 100MB.
    • Enable Timeout Requests, and set to 60 seconds or less.
    • Disable Robust Exception Handling on production servers.

Web Application-level Security:

  • Use secure HTTP to transfer data and/or when logged into ‘administration’ secutions of your web application.
  • Timeout sessions after 15 minutes and on browser close.
  • Provide multi-level login processes. For example, lock the application after 3 failed attempts for a period of 10 minutes.
  • Do not identify whether the username or password are incorrect, simply notify the user that their login failed and that they must try again.
  • Encrypt passwords stored in the database with a standard such as SHA-256 or ’stronger’.
  • Use CAPTCHAs (textual and aural) to prevent automated robots hacking into your application.
  • Run regular penetration tests on your application to identify potential problems.
  • Encrypt credit card information held in the database or other storage mechanism. Only store credit card data in line with the PCI DSS regulations.

Code-level Security:

  • Application.cfc – Set the scriptProtect Application variable to true to enable application-wide cross-site script protection.
  • CFQueryParam – This tag, importantly, verifies the data type of a query parameter and, for RDBMSs that support bind variables, enables ColdFusion to use bind variables in the SQL statement. Bind variable usage enhances performance when executing a cfquery statement multiple times. There are limitations to the use of the cfqueryparam tag. In ColdFusion 7 for example, you cannot use them in queries using the cachedWithin attribute. Similarly, they cannot be used in ORDER BY clauses, although the use of conditional logic should resolve the need for order by variables.
  • Functions – As a rule of thumb, validate all the data being passed into a query prior to it being used. ColdFusion MX 7 saw the introduction of the isValid() function. This function tests whether a value meets a validation or data type rule and can be used to replace a large number of type-specific functions such as isArray(), isBinary(), isBoolean(), isDate(), isNumeric() and isSimpleValue() etc.
  • Stored Procedures – I often favour the use of stored procedures over standard queries. Not only do they add an additional level of performance, they provide an additional level of security; ColdFusion does not do any raw processing of queries in the web code, it simply passes variables down the wire to the database server.

Conclusion

The goal of the PCI Data Security Standard is to protect cardholder data that is processed, stored or transmitted by merchants. The security controls and processes required by PCI DSS are vital for protecting cardholder account data, including the PAN – the primary account number printed on the front of a payment card. Merchants and any other service providers involved with payment card processing must never store sensitive authentication data after authorisation. This includes sensitive data that is printed on a card, or stored on a card’s magnetic stripe or chip – and personal identification numbers entered by the cardholder.

By following the points made above, you will go a long way to meeting the PCI DSS guidelines, whilst also securing your infrastructure and applications in a more general sense.

Caveat: The views and comments written in this article are provided as a guideline. I hold no responsibility for the security of your applications and data based upon the information provided.

Adobe recently announced, in conjunction with Amazon, that they would bring LiveCycle to Amazon’s Elastic Compute Cloud (EC2). To quote Adobe:

Adobe is now offering developers subscribed to the Adobe Enterprise Developer Program access to their own virtual instance of LiveCycle ES through LiveCycle ES Developer Express. LiveCycle ES Developer Express provides a pre-configured, virtualized installation of LiveCycle ES Solution Components in a self-contained development environment. LiveCycle ES Developer Express is hosted on the Amazon Elastic Compute Cloud (Amazon EC2). AEDP members can test, build, store and develop their applications in a cloud-base environment where all LiveCycle ES applications are pre-configured and running. The Adobe Enterprise Developer Program will offer a minimum of 10 hours of runtime per month, with additional hours to be available separately.

What is cloud computing and why is it important?

The term cloud computing, as used by some commentators, refers to the use of scalable, real-time, Internet-based information technology services and resources. This somewhat nebulous concept incorporates software as a service (SaaS), utility computing, Web 2.0 and other recent technology trends. The common theme stresses reliance on the Internet for satisfying the computing needs of users, without them needing knowledge of, expertise with, or control over the technology infrastructure that supports them. An often-quoted example is Google Apps, which provides common business applications online that are accessed from a web browser, while the software and data are stored on Google servers.

The cloud element of cloud computing derives from a metaphor used for the Internet, from the way it is often depicted in computer network diagrams, and is an abstraction for the complex infrastructure it conceals.

How do Adobe and Amazon fit into the equation?

Adobe and Amazon have similar goals. They both want to gain more share of the enterprise market. Amazon needs to convince the enterprise that its version of the cloud is capable of supporting the demands of enterprise applications. On the other hand Adobe wants to convince the developers who already use AWS that LiveCycle is the platform of choice for the enterprise.

What is Adobe LiveCycle?

Adobe LiveCycleAdobe’s LiveCycle Enterprise Suite is a J2EE-based server software product used to build applications that automate a broad range of business processes for enterprises and government agencies.

LiveCycle combines technologies for data capture, information assurance, document output, content services, and process management to deliver solutions such as account opening, services and benefits enrollment, correspondence management, request for proposal processes, and other manual based workflows.

What are Amazon Webservices?

Amazon Webservices LogoSince early 2006, Amazon Web Services (AWS) has provided companies of all sizes with an infrastructure web services platform in the cloud. With AWS you can requisition compute power, storage, and other services–gaining access to a suite of elastic IT infrastructure services as your business demands them. With AWS you have the flexibility to choose whichever development platform or programming model makes the most sense for the problems you’re trying to solve. You pay only for what you use, with no up-front expenses or long-term commitments, making AWS a cost-effective way to deliver applications to customers and clients.

How do they fit together?

Essentially, Adobe has put a Red Hat JBoss J2EE stack on AWS and deployed LiveCycle on the stack. Adobe state that this platform is purely for prototyping, developing and testing applications, rather than production environments, but that is likely to change.

The future

Deploying LiveCycle on AWS has wider implications, not only for Adobe products. By setting up a J2EE stack on AWS it makes it possible to deploy any Java-based application; yes that does mean one developed in Adobe’s ColdFusion or indeed its chief rival, Railo.

ColdFusion is 13 years old. That make makes it the daddy of the web world! It does not make it any less hip or useful than the relatively new kids on the block.

Take this scenario. A company I once worked for had what can be described as a business directory built upon a licensed, yet bastardised, version of a popular ColdFusion-based CMS. It didn’t work that well! The decision was made to redevelop the application in Java. It took two years to reach the same level of functionality! What happened next? Ruby-on-Rails is what! The rest is history and beyond the topic of this post.

So, in effect, the application almost went full-circle in its development paradigm — both ColdFusion and Ruby-on-Rails can be considered Rapid Application Development environments, Java, certainly not. Why did the decision makers not stick with ColdFusion and put time aside to actually build it properly in the first place? To put it simply, they lost faith in ColdFusion; it was largely mis-understood.

The weakness of every programming language does not lie with the language itself per se — albeit it can have an important influencing factor — but rather with the ability, or indeed inability, of the developer to leverage the language in the most efficient and optimal way.

ColdFusion, like every other programming language has had and I’m sure still does have its fair share of poor developers; those people simply working with it as a means-to-an-end, rather than those passionate about the language, those people programming without understanding the fundamentals of programming or the implications of their poorly written code. This is apparent from .NET to Java, ColdFusion to Ruby, JavaScript to ActionScript.

Let’s not dilly-dally, bicker or insult one another about which is best, which one is dying and which one is not worth the computer it is compiled on. What is important is to understand the merits of each language and decide which one best suits the application, not only in technical terms, but also in terms of time-to-market, cost of development, availability of a skilled workforce etc.

ColdFusion, whether rightly or wrongly in some people’s opinion, can sit proudly amongst its peers and provide a truly compelling alternative.

Here’s how (in no particular order):

  1. Low Total Cost of Ownership – frequently, ColdFusion is described as expensive, it simply isn’t especially if you consider the natively supported functions. But to put it bluntly, if your company cannot afford the cost of ColdFusion standard, or indeed ColdFusion hosting, you have bigger things to worry about regarding the profitability of the company; you won’t be able to afford much of anything! The problem becomes not the product. ColdFusion applications are quicker to develop and developers are vastly cheaper to employ than their peers in Java or Ruby, just look at ITJobsWatch for examples.
  2. Rapid Application Development – ColdFusion vastly simplifies tasks. What would take other languages numerous lines of code to produce is efficiently encapsulated either in a tag or function or as a setting in the administrator. This is a simplistic yet indicative example: where else can you connected to a database simply with one line of code or indeed simply by name? ColdFusion changed the idea of specifying development time in terms of months and years to weeks and months or small features a matter of hours and days. Simplicity is not the mother or all evil. To be pragmatic, simplification reduces costs.
  3. Rich Internet Applications – ColdFusion may or may not have pioneered the RIA paradigm, but it has played a significant supporting role to Flash and now Flex. ColdFusion natively supports Flash remoting, providing the all important data access tier.
  4. Platform Maturity – ColdFusion 8 is built upon the latest version of Java (1.6). Along with internal improvements to the ColdFusion application, this has afforded ColdFusion unprecedented speed improvements and stability.
  5. Language Maturity – with each major release of ColdFusion comes many language enhancements added to the core. This means that previous addons, for example image manipulation, which came at a premium are now standard. Adobe and other companies that produce CFML engines are now participating in a CFML advisory committee, which aims to set standards for the core language. This is not only a sign of maturity but a letter of intent by the industry that will mean your application will work on any engine, assuming no proprietary functionality is used.
  6. The Ultimate Middleware – ColdFusion sits comfortably between any backend and front end system. Be it interfacing with a host of databases, Java, .NET, COM, Corba or connecting to classic HTML or rich Flash, Flex and AJAX frontends with little or no configuration.
  7. Feature Rich – what other web technology natively supports PDF generation, charting, enterprise-level search, AJAX, image manipulation, Atom and RSS creation, Zip and JAR file manipulation, a server monitor, Flex integration, encryption libraries, all important database connectors, webservice creation, XML manipulation, inbuilt reporting application (similar to Crystal Reports), email, FTP to name but a few? I hazard a guess at none, unless you’re happy to pay a premium.
  8. Platform Independent – since ColdFusion 6, when Macromedia redeveloped the entire application in Java, ColdFusion has been platform independent. You can install it on practically any machine.
  9. OpenSource Alternatives – BlueDragon and Railo are both significant alternatives to Adobe ColdFusion and both have opensource alternatives, the latter of the two having recently joined the JBoss community. Adobe are also considering providing a free edition to academic institutions.
  10. The Future – many commentators have mentioned Hibernate as a significant addition to the next release of ColdFusion, version 9. But having seen the prerelease notes, that is not all that will be added. Alas I’m under NDA, but rest assured, there is going to be a significant intake of breath when developers get hold of the next release. ColdFusion 8 was firmly geared towards middle management with fuzzy additions, ColdFusion 9 is set to re-address the balance with compelling language and functionality enhancements.

ColdFusion evangelism needs to step up a gear! Adobe certainly doesn’t afford much marketing budget to the product, prefering The Community do the hard work. It is not always easy convincing the decision makers that ColdFusion is a good product of choice, without Adobe’s unnerving support, but we have to work hard, break down those barriers, encroach on events outside the comfortable sphere of the ColdFusion world and demonstrate ColdFusion’s match-winning ability.

ColdFusion isn’t dying, it’s simply niche. Every niche has its place.

UPDATE: If you would like to view the ensuing debate regarding ColdFusion prompted by Aral Balkan, feel free to do so. This post should serve as a positive reminder of ColdFusion’s virtues, alongside the need for a balanced and polite debate.

Using Ant with Eclipse

If you’re currently not using Eclipse as your development tool of choice, you certainly should be! Eclipse is an open source community whose projects are focused on building an open development platform comprised of extensible frameworks, tools and runtimes for building, deploying and managing software across the lifecycle.

Eclipse started out as a Java IDE and has continually grown from there. Plugins now include, amongst a plethora of others, the venerable Aptana, CFEclipse, SQL Explorer, Subclipse and, more recently, the Adobe-developed Flex Builder and ColdFusion-equivalent codenamed Bolt.

Apache Ant is a software tool for automating software build processes. It is implemented using the Java language, requires the Java platform, and was originally developed to automate the build of Java projects. However, since Ant was created as a simple, platform-independent tool, it can really be used to automate the build of anything you choose.

Ant uses XML to describe the build process and its dependencies, using a file commonly called build.xml. Using this file, Ant makes it trivial to integrate unit testing frameworks with the build process and has made it easy for web developers to adopt test-driven development, and even Extreme Programming.

Fortunately for us, if you download and run Eclipse, you already have Ant installed and so do not have any complex configuration to concern yourself with; well, at least initially.

Setting Up Eclipse

For the most part, Eclipse has all you need to get up and running with Ant pre-installed. However, most projects will include a release target which uses FTP to upload the files to a live server. The FTP ant task requires some extra libraries (.jar files):

commons-net-*.jar
jakarta-oro-*.jar

(The library files can be downloaded from here).

Copy the files into the ant lib folder of your Eclipse install. The folder is commonly located here:

C:\Program Files\Eclipse\plugins\org.apache.ant_*\lib

(The asterix * refers to the Ant version).

Next, go to Window > Preferences and select Ant > Runtime. In the Classpath tab, select Ant Home Entries, click Add External JARs… and select the 2 files you copied to the ant lib folder.

A Typical Ant Project Setup

A project with ant build scripts should have the following within the repository:

  • build.xml (the actual ant build script)
  • build.properties.template (a template for individual build.properties files)
  • an optional top level lib folder (containing jar files for external ant tasks)

Examples of the build.xml and build.properties.template files can be downloaded from here.

Create Your Own build.properties File

Make a copy of the build.properties.template file (name it build.properties) and set the values to fit your local setup (in most cases, the only property you may want to change is deploy.dir.local which is the path to the site on your local machine).

This file should never be committed to the repository (the repository should be set to ignore it anyway).

Basic Build Tasks

The build file should have a deploy.local task. This task builds the project and copies it to your local webserver (the path to the web server folder will be defined in the build.properties file).

Most projects should also have a deploy.dev task to copy the latest work to the dev server so that other people can view it.

Setting Up an Automatic Build

To make things easy, you can set deploy.local to run every time you save a file. This is called an automatic build.

The process for setting up automatic build is quite convoluted. I’m not sure why but this is the best way I’ve found to make it work.

Step 1: Add the build file to your ant view

Click the add button and select the build.xml file from the project. You can also drag the build.xml file onto the ant view (To add the ant view to your perpective, go to Window > Show View > Other…)

Step 2: Run as Ant Build

In your ant view, right click the newly added build file and select Run As > Ant Build… In the dialog window, select the ‘Hide internal targets not selected for execution’ option in the Targets tab. You can rename the builder in the box at the top of the window if you wish (I usually remove the trailing ‘build.xml’. Click Apply and Close.

Step 3: Setup automatic build

Right click on the project, select Properties, then Builders. Click Import. Before closing the screen, highlight the imported build and select edit. Go to the Targets tab select clean for ‘After a clean’ and deploy.local for ‘Auto build’. Apply the changes and close.

Step 4: Enable Auto Build

Go to Project > Build Automatically

Acknowledgment: Thanks should go to Martin Laine for his help and guidance which resulted in this article.

A common need in SQL is the ability to iterate over a list as if it were an array. In SQL it is not possible to declare arrays, unlike other programming languages such as ColdFusion, ActionScript and Java. Fortunately, there is a way around this problem: use a User-Defined Functions (UDFs) to create a tabular version of the data. Arrays are, after all, essentially tabular data (at their simplest, one dimension level).

A User-Defined Function, is a function provided by the user of a program or environment. In SQL databases, a user-defined function provides a mechanism for extending the functionality of the database server by adding a function that can be evaluated in SQL statements.

The Function Code

Below is the complete function definition:

CREATE FUNCTION dbo.udf_ListToTable
(
	@LIST 		NVARCHAR(4000), 
	@DELIMITER 	NVARCHAR(10) = ','
)
RETURNS @ListTable TABLE 
(
	Item NVARCHAR(200)
)
AS
BEGIN
	DECLARE @LenDel 	INT
	DECLARE @Pos 		INT
	DECLARE @Item 		NVARCHAR(200)
 
	--Get the length of the delimiter, use hack to get around LEN(' ') = 0 issue
	SET @LenDel = LEN(@DELIMITER + '|') - 1 
 
	SET @Pos = CHARINDEX(@DELIMITER, @LIST)
	WHILE @Pos > 0
	BEGIN
		--Get the item
		SET @Item = SUBSTRING(@LIST, 1, @Pos-1)
		--Add it to the table (if not empty string) 
		IF LEN(LTRIM(@Item)) > 0
			INSERT @ListTable (Item) VALUES (LTRIM(@Item))
		--Remove the item from the list
		SET @LIST = STUFF(@LIST, 1, @Pos+@LenDel-1, '')
		--Get the position of the next delimiter
		SET @Pos = CHARINDEX(@DELIMITER, @LIST)		
	END
 
	--Add the last item to the table (if not empty string) 
	IF LEN(LTRIM(@LIST)) > 0
		INSERT @ListTable (Item) VALUES (LTRIM(@LIST))
 
	RETURN 
END
GO

The function simply loops over the list passed into the function. Each list item is then inserted into the variable named @ListTable, which is of type TABLE. The @ListTable variable is then returned out of the function and can be handled the same as any other table.

The Function In Use

A simple demonstration is as follows:

INSERT INTO tableName (column1, column2, column3, column4)
SELECT @variable1, @variable2, myTable.item, GETDATE()
FROM dbo.udf_ListToTable(@list,',') AS myTable

In this example, we insert the same information (@variable1, @variable2) for every instance of an item found in myTable.

This is useful, for example, if you want to apply a setting to a group of users. The group of users could be contained in a list that needs to be parsed as a table, whilst the individual setting details are contained in the other variables.

Download the Code

Download the code, rename the file to .sql and run on your database instance. You will then be able to reference the function in your Stored Procedures.

Every seasoned developer will know that protecting your website from a hacker is a top priority, whether for your own reputation or for maintaining your company’s reputation and log-term revenue prospects.

Why should you be worried about security?

The Web is changing many of the assumptions that people have historically made about computer security and publishing. As the Internet makes it possible for web servers to publish information to millions of users, it also makes it possible for computer hackers, crackers, criminals, vandals, and other “bad guys” to break into the very computers on which the web servers are running. Once subverted, web servers can be used by attackers as a launching point for conducting further attacks against users and organisations.

It is considerably more expensive and more time-consuming to recover from a security incident than to take preventative measures ahead of time.

This blog post started on the premise of protecting your website from a SQL Injection Attack. However, it is also appropriate to discuss, at a relatively high level, how to secure your server architecture and applications.

Server-Level Security

  • Separate web- and database-servers on to different physical machines.
  • Secure the web- and database-servers with traditional techniques. Only authorised accounts should have the capabilities to run tasks on the machine. That means not giving admin-rights to the user account.
  • Keep servers up-to-date with the latest patches and software releases.
  • Minimise the number of services running on the server. This means limiting the services to only those required for the web- or database-servers to function.
  • Secure information in transit between servers. This may mean physically securing the network to prevent evesdropping via encryption or obfuscating the data amongst innocuous ‘noise’.
  • Secure the database server behind a firewall.

Application-Level Security

  • Separate ColdFusion, the webserver and database server user accounts. They should never be under the same system account.
  • Create a database user specifically for your ColdFusion datasource and restrict it to only the activities required for the application. The user should not have database-owner rights, access to databases not relating to the application or access to the system tables.
  • Revoke privileges in the ColdFusion datasource definition to prevent the SQL commands CREATE, DROP, GRANT, REVOKE and ALTER.
  • General settings in the ColdFusion Administrator:
    • Check the Disable access to internal ColdFusion Java components option.
    • Check the Enable Global Script Protection option.
    • Add a Missing Template Handler.
    • Add a Site-wide Error Handler.
    • Reduce the Maximum size of post data from 100MB.
    • Enable Timeout Requests, and set to 60 seconds or less.
    • Disable Robust Exception Handling on production servers.

Code-Level Security

  • Application.cfc – Set the scriptProtect Application variable to true to enable application-wide cross-site script protection.
  • CFQueryParam – This tag, importantly, verifies the data type of a query parameter and, for RDBMSs that support bind variables, enables ColdFusion to use bind variables in the SQL statement. Bind variable usage enhances performance when executing a cfquery statement multiple times.
    <cfquery name="qry" datasource="#APPLICATION.dsn#">
    SELECT column1, column2, column3
    FROM tableName
    WHERE column4 = <cfqueryparam value="#variable1#" cfsqltype="cf_sql_bit" />
    AND column5 LIKE <cfqueryparam value="%#variable2#%" cfsqltype="cf_sql_varchar" maxlength="200" />
    AND column6 IN (<cfqueryparam value="#variable3#" cfsqltype="cf_sql_integer" list="true" />)
    </cfquery>

    There are limitations to the use of the cfqueryparam tag. In ColdFusion 7 for example, you cannot use them in queries using the cachedWithin attribute. Similarly, they cannot be used in ORDER BY clauses, although the use of conditional logic should resolve the need for order by variables.

  • Functions – As a rule of thumb, validate all the data being passed into a query prior to it being used. ColdFusion MX 7 saw the introduction of the isValid() function. This function tests whether a value meets a validation or data type rule and can be used to replace a large number of type-specific functions such as isArray(), isBinary(), isBoolean(), isDate(), isNumeric() and isSimpleValue() etc.
  • Stored Procedures – I often favour the use of stored procedures over standard queries. Not only do they add an additional level of performance, they provide an additional level of security; ColdFusion does not do any raw processing of queries in the web code, it simply passes variables down the wire to the database server.

Additional Resources

ColdFusion Becomes a Teenager

Today ColdFusion moved into the next stage of its life and became a teenager, hopefully not a precocious one!

Happy 13th Birthday ColdFusion.

Adobe ColdFusion has had a long and illustrious life. The first version of ColdFusion–written almost entirely by one person, JJ Allaire and then called “Cold Fusion”–was released in 1995. This first version, although revolutionising how web applications were built, was primitive by modern standards, doing little more than database access.

Although originally built in Visual C++, Allaire, around 1999, took the decision to rewrite the entire ColdFusion engine in Java–a project named “Neo”–which would allow for greater portability among different platforms. The rewrite, released under the monicker MX 6, would prove to be somewhat problematic and a wholescale update to the version resulted.

In 2001 Allaire was acquired by Macromedia. This union brought with it the integration of Macromedia’s Flash platform via Flash Remoting; a huge step towards rich Internet applications.

In 2005 it was the turn of Macromedia to be acquired and they merged with Adobe. A period of instability in the ColdFusion world resulted, brought about by the knowledge that Adobe was a company that developed tools, not programming languages. However, following a successful release of ColdFusion 8 in 2007 and the announcement that a version 9 would be developed, code-named “Centaur”, fears about ColdFusion’s future have subsided–albeit the continued debate over “ColdFusion is Dead” remains boiling in the background.

The primary distinguishing feature of ColdFusion is its associated scripting language, ColdFusion Markup Language (CFML), which compares favourably to its rivals, JSP, ASP.NET, or PHP and resembles HTML in syntax. “ColdFusion” is often used synonymously with “CFML”, but it should be noted that there are additional CFML application servers besides ColdFusion, and that ColdFusion supports programming languages other than CFML, such as server-side Actionscript and embedded scripts that can be written in a JavaScript-like language, known as CFScript. Adobe ColdFusion also includes native support for Flex, PDF, Verity and the embedded Derby database amongst a host of other features.

ColdFusion 9 is set to be an exciting release, much like its predecessor, with more features added to the core tag set, whilst also integrating other technologies such AIR and Hibernate.

Exciting times lay ahead. Let’s hope Adobe takes full advantage with such a fine product.

See Also:

With the release of ColdFusion MX 7 came the introduction of the Application.cfc ColdFusion component. This component replaced the traditional Application.cfm and OnRequestEnd.cfm ColdFusion application templates. Furthermore, if Application.cfc is present, both of these templates are ignored by the application.

In addition to replacing the Application.cfm, the Application.cfc introduced a number of built in methods that handle specific events. These events, as discussed in detail below, allow for a greater control over events within the application.

Application Variables

The THIS scope in the Application.cfc contains several built-in variables that allow you to set the properties of the application.

The following cfscript briefly outlines the variables that you can set to control the application’s behaviour.

<cfscript>
//the application name (should be unique)
THIS.name = "ApplicationName";
//how long the application variables persist
THIS.applicationTimeout = createTimeSpan(0,2,0,0);
//define whether client variables are enabled
THIS.clientManagement = false;
//where should we store them, if enabled?
THIS.clientStorage = "registry"; //cookie||registry||datasource
//define where cflogin information should persist
THIS.loginStorage = "session"; //cookie||session
//define whether session variables are enabled
THIS.sessionManagement = true;
//how long the session variables persist?
THIS.sessionTimeout = createTimeSpan(0,0,20,0);
//define whether to set cookies on the browser?
THIS.setClientCookies = true;
//should cookies be domain specific
//i.e. *.domain.com or www.domain.com
THIS.setDomainCookies = false;
//should we try to block cross-site scripting?
THIS.scriptProtect = false;
//should we secure our JSON calls?
THIS.secureJSON = false;
//use a prefix in front of JSON strings?
THIS.secureJSONPrefix = "";
//used to help ColdFusion work with missing files
//and directory indexes. tells ColdFusion not to call
//onMissingTemplate method.
THIS.welcomeFileList = "";
//define custom coldfusion mappings.
//Keys are mapping names, values are full paths
THIS.mappings = structNew();
//define a list of custom tag paths.
THIS.customTagPaths = "";
</cfscript>

Method Summary

Below is a brief discussion of the built-in event methods available to the Application.cfc. Since the Application.cfc is a regular ColdFusion component, you can also implement your own methods alongside the built in ones (assuming the names are uniquely different).

The onApplicationStart Method

Runs when the application first starts up: when the first request for a page is processed or the first CFC method is invoked by an event.

<cffunction name="onApplicationStart" returnType="boolean" output="false">
	<cfreturn true />
</cffunction>

This method is typically used to initialise code; for example to to set variables, such as datasource, into the APPLICATION scope, or create Singleton instances of ColdFusion components.

For example:

The following example creates structures in tha application scope to store general configuration settings and Singleton objects that can be later referenced by the application framework.

<cffunction name="onApplicationStart" returnType="boolean" output="false">
	<cfscript>
	// INITIALISE CONFIGURATION VARIABLES AND APPLICATION BUSINESS COMPONENTS
	// **********************************************************************
	// LOAD COMMON SITE VARIABLES INTO APPLICATION SCOPE
	// create structure to hold configuration settings
	APPLICATION.strConfig = structNew();
	//site-wide datasource(s)
	APPLICATION.strConfig.datasource = "DatasourceName";
	// default records per page for pagination
	APPLICATION.strConfig.recordsPerPage = 15;
	// **********************************************************************
	// LOAD PERSISTENT OBJECTS INTO APPLICATION SCOPE
	// data for object instantiation
	strArgs	= structNew(); // flush strArgs
	strArgs.datasource = APPLICATION.strConfig.datasource;
 
	// create structure to hold objects
	APPLICATION.strObjs = structNew();
	APPLICATION.strObjs.objUserManager = createObject("component","com.whatley.user.UserManager").init(argumentCollection=strArgs);
	//etc...
 
	// instantiate utility service objects
	APPLICATION.strObjs.objEmailServices = createObject("component","com.whatley.service.Email");
	APPLICATION.strObjs.objFileServices = createObject("component","com.whatley.service.File");
	APPLICATION.strObjs.objQueryServices = createObject("component","com.whatley.service.Query");
	//etc...
 
	// native coldfusion objects
	APPLICATION.strObjs.objServiceFactory = createObject("java","coldfusion.server.ServiceFactory");
 
	// **********************************************************************
	return true;
	</cfscript>
</cffunction>

Since the objects above are created as Singletons, we do not have to create or destroy objects throughout the application, but simply reference the object held in memory. This is efficient, but of course, would not be suitable for per-session objects, such as shopping carts.

For example:

Referencing and invoking an object from the APPLICATION scope:

<cfinvoke object="APPLICATION.strObjs.objUserManager" method="getUser" returnvariable="qryGetUser">
	<cfargument name="userId" value="#SESSION.strUser.userId#" />
</cfinvoke>

The onApplicationEnd Method

Runs when the application stops: when the application times out or the service is stopped.

<cffunction name="onApplicationEnd" returnType="void" output="false">
	<cfargument name="applicationScope" required="true" />
</cffunction>

This method is typically used to clean-up currently activities, save the current state of the application to a database or log the application’s end to a file. The latter can be useful to help determine when and why an application ended.

Below is a simple example of how you could implement a simple log:

<cffunction name="onApplicationEnd" returnType="void" output="false">
	<cfargument name="applicationScope" required="true" />
        <cflog file="#THIS.Name#" type="Information"
        	text="Application #ARGUMENTS.applicationScope.applicationName# Ended" />
</cffunction>

Notes:

  • The method is not associated with an individual request so you cannot use it to display data to a user.
  • If you call this method explicity, ColdFusion does not end the application, but does execute the code within the method.
  • The method can access the SERVER scope directly, but does not have access to the SESSION and REQUEST scopes.

The onMissingTemplate Method

Triggered when the user requests a ColdFusion template that doesn’t exist.

<cffunction name="onMissingTemplate" returnType="boolean" output="false">
	<cfargument name="targetpage" required="true" type="string" />
	<cfreturn true />
</cffunction>

ColdFusion invokes this method when it encounters a file not found condition, that is, when a URL specifies a CFML page that does not exist. This is an important addition to ColdFusion 8 and allows missing template errors (also known as HTTP 404 errors) to be captured more efficiently by the application framework.

The onRequestStart Method

Runs before the request is processed.

<cffunction name="onRequestStart" returnType="boolean" output="false">
	<cfargument name="thePage" type="string" required="true" />
	<cfreturn true />
</cffunction>

This method is great for user authorisation and login handling and for request specific variable initialisation. For example, you could use this method to log statistics to a database (performance and usage).

As this method runs at the beginning of a request, we can also use it to fire other events. In the example below, I reinitialise the Application which enables me to refresh objects held in memory that may have changed during code development or release.

<cffunction name="onRequestStart" returnType="void" output="false">
	<cfscript>
	//flush the application scope
	if ((CGI.server_name == "localhost") || (structKeyExists(URL,'refresh') && structKeyExists(URL,'password') && URL.password == "p455w0rd"))
	{
		onApplicationStart();
	}
	return true;
	</cfscript>
</cffunction>

The onRequest Method

Runs before the request is processed, but after onRequestStart.

<cffunction name="onRequest" returnType="void">
	<cfargument name="thePage" type="string" required="true" />
	<cfinclude template="#ARGUMENTS.thePage#" />
</cffunction>

This event handler provides an optional request filter mechanism for ColdFusion page requests. Use it to intercept requests to target pages and override the default behavior of running the requested pages. You can use this method to do preprocessing that is required for all requests. Typical uses include filtering and modifying request page contents (such as removing extraneous white space), or creating a switching mechanism that determines the exact page to display based on available parameters.

The onRequestEnd Method

Runs at the end of the request when all pages have been processed.

<!--- Runs at end of request --->
<cffunction name="onRequestEnd" returnType="void" output="false">
	<cfargument name="thePage" type="string" required="true" />
</cffunction>

This method can be useful for gathering performance metrics, or for displaying dynamic footer information (although I wouldn’t generally put display code in an Application.cfc).

For example:

Log the CGI variables to a database table.

<cffunction name="onRequestEnd" returnType="void" output="false">
	<cfset var qryInsertStats = queryNew('tempCol')>
	<cfquery name="qryInsertStats" datasource="#APPLICATION.strConfig.datasource#">
	INSERT INTO tbl_site_stats (template,query_string,referer,user_agent,remote_addr,datetime)
	VALUES
	(
		<cfqueryparam value="#CGI.PATH_INFO#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.QUERY_STRING#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.HTTP_REFERER#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.HTTP_USER_AGENT#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#CGI.REMOTE_ADDR#" cfsqltype="cf_sql_varchar" />
		<cfqueryparam value="#now()#" cfsqltype="cf_sql_datetime" />
	)
	</cfquery>
</cffunction>

The onError Method

Triggered when an error is encountered that is not caught by a try/catch block.

<!--- Runs on error --->
<cffunction name="onError" returnType="void" output="false">
	<cfargument name="exception" required="true" />
	<cfargument name="eventname" type="string" required="true" />
	<cfdump var="#ARGUMENTS#" />
        <cfabort />
</cffunction>

This method is used to handle errors in an application-specific manner. This method overrides any error handlers that you set in the ColdFusion Administrator or in cferror tags. It does not override try/catch blocks.

For example:

The following displays a friendly, static error page to the user if it is not a development server whilst also logging the error. If the error is on development, simply dump the error to screen for debugging.

<cffunction name="onError" returnType="void" output="true">
	<cfargument name="exception" required="true" />
	<cfargument name="eventName" type="string" required="true" />
	<cfif CGI.server_name neq "localhost" and CGI.server_name neq "127.0.0.1">
		<!--- Live application, handle error --->
		<cfinclude template="error/error.htm">
		<!--- Log all errors. --->
	        <cflog file="#THIS.Name#" type="error"
	            text="Event Name: #ARGUMENTS.Eventname#" >
	        <cflog file="#THIS.Name#" type="error"
	            text="Message: #ARGUMENTS.Exception.message#">
	        <cflog file="#THIS.Name#" type="error"
	            text="Root Cause Message: #ARGUMENTS.Exception.rootcause.message#">
	<cfelse>
		<!--- dump error for Staging and Development --->
		<cfif len(ARGUMENTS.eventName)>
			<cfdump var="#ARGUMENTS.eventName#" />
		</cfif>
		<cfdump var="#ARGUMENTS.exception#" />
	</cfif>
</cffunction>

The onSessionStart Method

Runs when your session starts.

<cffunction name="onSessionStart" returnType="void" output="false">
</cffunction>

This method is used for initialising SESSION-scoped data, such as a shopping basket and application form.

For example:

<cffunction name="onSessionStart" returnType="void" output="false">
	<cfscript>
	SESSION.start = now();
	SESSION.strShoppingBasket = structNew();
	SESSION.strShoppingBasket.items = 0;
	</cfscript>
</cffunction>

The onSessionEnd Method

Runs when session ends

<cffunction name="onSessionEnd" returnType="void" output="false">
	<cfargument name="sessionScope" type="struct" required="true" />
	<cfargument name="appScope" type="struct" required="false" />
</cffunction>

Use this method for any clean-up activities when the session ends. A session ends when the session is inactive for the session time-out period. You can, for example, save session-related data, such as shopping basket contents or whether the user has not completed an order, in a database, or do any other required processing based on the user’s status. You might also want to log the end of the session, or other session related information, to a file for diagnostic use.

Adobe Livedocs has a whole section dedicated to the Application.cfc.

I have created an example Application.cfc, which is available for download.

« Older entries