Coldfusion 9 Dev
Coldfusion 9 Dev
ADOBE COLDFUSION 9
iii
Contents
Chapter 1: Whats New
Whats new in ColdFusion 9.0 Update 1
Whats new in ColdFusion 9
................................................................................ 1
............................................................................................ 5
Chapter 2: Introduction
Using the Developing ColdFusion Applications guide
About Adobe ColdFusion 9 documentation
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
iv
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
Configure ORM
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575
Using queries
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584
Performance optimization
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 625
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 688
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 722
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 765
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890
Using cfspreadsheet
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 892
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 930
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 959
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 982
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1048
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1093
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1122
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1125
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1149
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1170
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1207
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1243
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1254
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1276
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1292
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1308
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1311
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1316
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1320
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1334
Language
Caching
IIS 7
dbinfo
imap
pop
ldap
feed
Area
ColdFusion Ajax
operation
While using cffileupload, the url attribute is now optional and it defaults to
cgi.script_name
The fileupload control now passes session information implicitly to the target page if
session management is turned on either in Application.cfc or Application.cfm.
ColdFusion.Autosuggest.getAutosuggestObject
ColdFusion.Layout.disableSourceBind
ColdFusion.Layout.enableSourceBind
Coldfusion.fileUpload.setUrl
ColdFusion.grid.getSelectedRows
ColdFusion.Map.show
ColdFusion.Map.hide
ColdFusion.Map.refresh
ColdFusion.Grid.getTopToolbar
ColdFusion.Grid.getBottomToolbar
ColdFusion.Grid.showTopToolbar
ColdFusion.Grid.hideTopToolbar
ColdFusion.Grid.showBottomToolbar
ColdFusion.Grid.hideBottomToolbar
ColdFusion.Grid.refreshTopToolbar
ColdFusion.Grid.refreshBottomToolbar
Area
ORM
SpreadSheet
Performance improvements for formatting huge number of rows and columns using the
SpreadSheet format functions
AIR integration
Flash Remoting
Cache file used by ActionScript ORM to track the operations on SQLite database is now
in the applicationStoragedirectory instead of applicationDirectory. You can specify the
location of the cahceDirectory in openSession API on syncmanager
Supports both Array and ArrayCollection for use in ActionScript Entity to represent a
collection in a database relationship
ActionScript ORM logs all the SQL statements that ORM uses to persist entities into the
SQLite database
The class SessionToken is dynamic and therefore, data can be stored on the token
returned from the ORM APIs
Area
Solr
Logging
Server monitoring
BlazeDS 4
Apart from overall improvement in the accuracy of indexing, the following enhancements:
Both the tags cfindex and cfsearch support the attribute categoryTree
ColdFusion generates log files for the following services: http, ftp, web service, Portlet,
Derby, and Feed
Enable/Disable logging: A new icon has been added in the Actions column of the Log
Files page (ColdFusion Administrator > Debugging & Logging)
Enhancements in this release help you use Server Monitoring effectively in load conditions.
ColdFusion Administrator has the following monitoring options: Enable monitoring,
Enable profiling, and Enable memory tracking.
OEM upgrades
Other enhancements
Ehcache 2.0
Hibernate 3.5.2
ExtJS 3.1
Solr 1.4
MySQL 5.1.11
Application.cfc lets you specify data source authentication details in the attribute
datasource
The ActionScript proxy class for PDF service has the following new attributes:
extracttext and extractimage
ORM support
ColdFusion Object-relational mapping (ColdFusion ORM) is a powerful Rapid Application Development (RAD)
solution to build data-centric applications. It provides a bridge between relational databases and ColdFusion
components by allowing you to build applications using only objects, without writing any SQL code. It uses the opensource Hibernate library as the underlying engine.
ColdFusion ORM provides:
on the server.
For more information, see Offline AIR Application Support.
Language enhancements
CFScript
Language constructs You can now use the following basic language constructs: throw, writedump, writelog,
location, and trace.
Script functions This release has introduced the following new functions implemented as CFCs: query, mail, http,
storedproc, pdf, and ftp.
Keywords This release has introduced keywords for abort, exit, include, param, property, rethrow, and throw.
Operations CFScript now supports import and new operations.
onServerStart
ColdFusion now supports a CFC with onServerStart method that runs only when the server starts. The function is
useful for application-independent tasks, such as instantiating the applications, configuring logging, or setting up the
scheduler.
For more details, see the section onServerStart in ColdFusion CFML Reference.
Nested cftransaction
UDF name conflict resolution for CFCs
Local scope
Var scope support anywhere in functions
Implicit getters and setters for cfproperty in CFCs
Geographical maps
Media player
Multi-file upload
Enhanced data grid
Improved Ajax plumbing
Enhanced auto-suggest
Accordion navigation
Progress indicator
cfspreadsheet tag
Generate PDFs from MS Word and MS PowerPoint automatically using the cfdocument tag
Generate PowerPoint presentations dynamically from HTML using the cfpresentation tag
Create Connect presentations from MS PowerPoint using the cfpresentation tag
For more information, see Office file interoperabilityOffice file interoperability.
Performance enhancements
Granular control over caching
ColdFusion 9 provides better control over caching.
The following features help to improve the performance of your application:
Caching specific objects. Includes the ability to put, get, and flush cached objects.
Setting cache dependencies
Setting idle timeout
Getting metadata about cached objects
For more information, see Optimizing ColdFusion applications.
In-memory files
In-memory files allow you to dynamically generate CFM files and execute them directly from memory. Memory-based
virtual file system speeds up the processing of transient data. In-memory files are not written to disk and are saved on RAM.
In ColdFusion, in-memory files help you simplify the execution of dynamic code. Though they function in the same
manner as disk files, they are faster. In-memory files are supported across all tags and functions that take file/directory
as input or output. They work in the same manner as files saved on the disk.
For more information, see Working with in-memory files.
Improved Clustering
This release supports serialization of query, array, and datetime types in CFC.
Database enhancements
DataDirect
This release supports DataDirect driver version 4.0 SP 1. The feature helps to enhance database operations by
providing the following features:
Support for MySQL (Enterprise and Commercial editions), Oracle11g, DB2v9.5, Informix 11, and SQL Server 2008
Support for IPv6
Option to set a default query timeout value
For more information, see the DataDirect Connect JDBC Support in the Configuring and Administering ColdFusion.
Note: By default, the datasource property MaxPooledStatements is set to 100 (and not 1000 as in the previous releases)
for the drivers DB2, Informix, MSSQLServer, Oracle, Sybase, and MySQL(DataDirect). Adobe recommends that you
maintain the default number of max pooled statements to avoid memory-related issues.
Code Analyzer
You can migrate code from ColdFusion 7 or ColdFusion 8 to ColdFusion 9.
For more information, see Using the Code Analyzer.
Service features
ColdFusion as a service
ColdFusion exposes many existing enterprise services as web services. You can access these services using SOAP and
AMF/Flash remoting.
The following are the exposed services:
cfpdf
cfImage
cfdocument
cfmail
cfpop
cfchart
You can secure the exposed services to prevent access by unknown applications and users. You can do this by
configuring the client IP address range to which services are accessible. You can also set up user access control for the
services.
Other enhancements
Server Manager
Server Manager is an AIR-based desktop application that allows you to centrally manage multiple ColdFusion servers
from one location.
The application enables ColdFusion server administrators to monitor and manage multiple servers and apply the
settings from one ColdFusion server to other ColdFusion servers.
Server Manager provides improved system management and minimizes errors by ensuring a consistent configuration
across multiple servers or clusters.
You can use Server Manager to:
10
PDF functionality
The following list includes new features and improved functionality:
IMAP support
You can query an IMAP server to retrieve and manage mails within multiple folders using the cfimap tag.
This feature lets you:
Retrieve messages and store information in a query object. You can also download attachments in a temporary
ColdFusion folder or a new folder.
JRE specifications
This release includes JRE version JRE 6 Update 14 for all platforms except Solaris which has the version JRE 6 Update 12.
11
Chapter 2: Introduction
The Developing Adobe ColdFusion 9 Applications guide provides tools for developing Internet applications using
Adobe ColdFusion. The guide is intended for web application programmers who are learning ColdFusion or want to
extend their ColdFusion programming knowledge. It provides a solid grounding in the tools that ColdFusion provides
to develop many different types of web applications of varying complexity.
Documentation set
The ColdFusion documentation set includes the following titles:
Book
Description
Describes system installation and basic configuration for Windows, Macintosh, Solaris, Linux, and AIX.
Describes how to perform ColdFusion administration tasks such as managing server settings, configuring
datasources, managing security, deploying ColdFusion applications, caching, setting up CFX tags,
monitoring server activity using the ColdFusion Server Monitor, and configuring web servers.
Describes how to develop your dynamic web applications. This book provides detailed information about
using the CFML programming language and ColdFusion features, such as ColdFusion Web Services,
ColdFusion Portlets, ColdFusion ORM, AJAX support, Flex and AIR integration, and integration with other
products and technologies such as Microsoft Office, OpenOffice, and SharePoint.
Provides descriptions, syntax, usage, and code examples for all ColdFusion tags, functions, and variables.
12
13
If the user requests a file that is a simple web page (often one with an HTM or HTML extension), the web server
fulfills the request and sends the file to the browser.
If the user requests a file that is a page that a web application server must process (one with a CFM, CFML, or
CFC extension for ColdFusion requests), the web server passes the request to the web application server. The
web application server processes the page and sends the results to the web server, which returns those results to
the browser. The following image shows this process:
1. W eb brow s er
reques ts a w eb page.
.
In te rn e t
W eb Server
5. T he w eb s erv er
s ends the output
to the brow s er.
A p p licatio n
Server
Because web application servers interpret programming instructions and generate output that a web browser can
interpret, they let web developers build highly interactive and data-rich websites, which can do tasks such as the
following:
About ColdFusion
Adobe ColdFusion is a rapid scripting environment server for creating dynamic Internet Applications. ColdFusion
Markup Language (CFML) is a tag-based scripting language that is easy to learn. CFML provides connectivity to
enterprise data and powerful built-in search and charting capabilities. ColdFusion enables developers to easily build
and deploy dynamic websites, content publishing systems, self-service applications, commerce sites, and more.
14
ColdFusion pages are plain text files that you use to create web applications. You can create your ColdFusion
applications by writing all the code manually or by using wizards (provided with some editors) to generate the majority
of the code for you.
Elements of ColdFusion
ColdFusion consists of the following core elements:
15
CFML increases productivity by providing a layer of abstraction that hides many low-level details involved with
Internet application programming. At the same time, CFML is powerful and flexible. ColdFusion lets you easily build
applications that integrate files, databases, legacy systems, mail servers, FTP servers, objects, and components.
CFML tags serve many functions. They provide programming constructs, such as conditional processing and loop
structures. They also provide services, such as charting and graphing, full-text search, access to protocols such as FTP,
SMTP/POP, and HTTP, and much more. The following table lists a few examples of commonly used ColdFusion tags:
Tag
Purpose
cfquery
Establishes a connection to a database (if one does not exist), executes a query, and returns results to the
ColdFusion environment.
cfoutput
Displays output that can contain the results of processing ColdFusion functions, variables, and expressions.
cfset
cfmail
Lets an application send SMTP mail messages using application variables, query results, or server files. (Another
tag, cfpop, gets mail.)
cfchart
Converts application data or query results into graphs, such as bar charts or pie charts, in Flash, JPG, or PNG
format.
cfobject
Invokes objects written in other programming languages, including COM (Component Object Model)
components, Java objects such as Enterprise JavaBeans, or Common CORBA (Object Request Broker Architecture)
objects.
16
ColdFusion Administrator
ColdFusion Administrator configures and manages the ColdFusion application server. It is a secure web-based
application that you can access using any web browser, from any computer with an Internet connection. It includes a
Server Monitor, which lets you see the status of your ColdFusion server.
For more information about ColdFusion Administrator, see Configuring and Administering ColdFusion.
Share session data with JSPs (Java Server Pages) and Java servlets.
Import custom JSP tag libraries and use them like ColdFusion custom tags.
Integrate with Java objects, including the J2EE Java API, JavaBeans, and Enterprise JavaBeans.
For more information on using J2EE features in ColdFusion, see Integrating J2EE and Java Elements in CFML
Applications on page 1125.
17
CFML Basics
CFML is a dynamic application development tool with many of the features of a programming language. These
features include functions, expressions, variables and constants, and flow-control constructs, such as if-then and loops.
CFML also has a language within a language, CFScript, which enables you to use a syntax like JavaScript for many
operations.
These elements and other basic CFML entities such as comments, data types, escape characters, and reserved words,
let you create complex applications.
Comments
ColdFusion comments have a similar format to HTML comments. However, they use three dash characters instead of
two; for example:
<!--- This is a ColdFusion Comment. Browsers do not receive it. --->
The ColdFusion server removes all ColdFusion comments from the page before returning it to the web server. As a
result, the page that a browser receives does not include the comment. Users cannot see the comment even if they view
the page source.
You can embed CFML comments in begin tags (not just tag bodies), functions calls, and variable text in number signs.
ColdFusion ignores the text in comments such as the following:
<cfset MyVar = var1 <!--- & var2 --->>
<cfoutput>#Dateformat(now() <!---, "dddd, mmmm yyyy" --->)#</cfoutput>
This technique can be useful if you want to temporarily comment out parts of expressions or optional attributes or
arguments.
You can also nest comments, as the following example shows:
<!--- disable this code
<!--- display error message --->
<cfset errormessage1="Oops!">
<cfoutput>
#errormessage1#
</cfoutput>
--->
This nesting is useful if you want to temporarily disable a section of code while you test your application.
You can embed comments within comments, however, use this technique carefully.
18
Note: You cannot embed comments inside a tag name or function name, such as <cf_My<!--- New --->CustomTag>.
You also cannot embed comments inside strings, as in the following example: IsDefined("My<!--- New -->Variable").
Tags
ColdFusion tags tell the ColdFusion server that it must process information. The ColdFusion server only processes tag
contents; it returns text outside ColdFusion to the web server unchanged. ColdFusion provides a wide variety of builtin tags and lets you create custom tags.
Tag syntax
ColdFusion tags have the same format as HTML tags. They are enclosed in angle brackets (< and >) and can have zero
or more named attributes. Many ColdFusion tags have bodies; that is, they have beginning and end tags with text for
processing between them. For example:
<cfoutput>
Hello #YourName#! <br>
</cfoutput>
Other tags, such as cfset and cfhttp, never have bodies. All the required information goes between the beginning
(<) character and the ending (>) character, as in the following example:
<cfset YourName="Bob">
Note: The cfset tag differs from other tags in that it does not have a body or arguments. Instead, the tag encloses an
assignment statement that assigns a value to a variable. The cfset tag can also call a function without assigning a value
to a result variable.
Sometimes, although the tag can have a body, it is unnecessary because the attributes specify all the required
information. You can omit the end tag and place a forward slash character before the closing (>) character, as in the
following example:
<cfprocessingdirective pageencoding="euc-jp" />
In most cases, you specify tag attributes directly in the tag using the format attributeName=" attributeValue" , as the
preceding example shows. However, as an alternative, you can place all the attributes in a structure and specify the
structure in a single attributeCollection attribute, using the following format:
<tagname attributeCollection="#structureName#">
When you use this format for all built-in ColdFusion tags except cfmodule, the tag must have only the
attributeCollection attribute. This format is useful when you use dynamic arguments, where the number and
values of the arguments to a tag can vary based on processing results. The following example shows this usage:
19
Note: The attributeCollection attribute used in the cfmodule tag and when calling custom tags directly is different
from the attributeCollection attribute for all other tags. In the cfmodule tag and in custom tags, you can mix the
attributeCollection attribute and explicit custom tag attributes. Also, in the cfmodule tag, the
attributeCollection attribute cannot contain the name and template attributes. Specify these attributes directly in
the cfmodule tag.
You can use the attributeCollection attribute in all tags except the following:
cfargument
cfelseif
cflogout
cfset
cfbreak
cffunction
cfloop
cfsilent
cfcase
cfif
cfparam
cfswitch
cfcatch
cfimport
cfprocessingdirective
cftry
cfcomponent
cfinterface
cfproperty
cfdefaultcase
cflogin
cfrethrow
cfelse
cfloginuser
cfreturn
Built-in tags
Built-in tags make up the heart of ColdFusion. These tags have many uses, including the following:
Manipulating variables
Creating interactive forms
Accessing and manipulating databases
Displaying data
Controlling the flow of execution on the ColdFusion page
Handling errors
Last updated 1/20/2012
20
Custom tags
ColdFusion lets you create custom tags. You can create two types of custom tags:
21
cfabort: abort
cfexit: exit
["message"];
["methodName"];
cfinclude: include
cfparam: param
"template";
The param attribute can now take any number of name=value pairs. Param can also take all the attributes of
<cfparam> as name-value pairs.
For example:
<cfscript>
param name="paramname" default="value" min="minvalue" max="maxvalue" pattern="pattern"
</cfscript>
cfrethrow: rethrow;
cfthrow: throw
"message";
For detailed information on the statement parameters, see the corresponding tag attribute description in the CFML
Reference.
Language-level tags with bodies
ColdFusion includes CFScript elements that provide the functions of the following language (compiler)-level tags,
which have bodies. These tags manage the execution of code within their bodies:
cflock: lock
cfthread: thread
cftransaction: transaction
Thread and transaction support also include functions, such as threadJoin and transactionCommit, that let you
manage any thread or transaction, whether you define it with a tag or a function.
The lock, thread, and transaction operations have the following syntax:
operationName attributeName1=value1 attributName2=value2...
{body contents }
cflock
The lock operation has no special characteristics or limitations. All cflock tag attributes are valid operation parameters.
The following code uses the lock operation:
22
cftransaction
To use the transaction operation you specify a begin action parameter. A transaction has the following general form:
TRANSACTION action="begin" [isolation="isolationValue"] {
transaction code
}
Within the transaction block you call the following methods to manage the transaction:
transactionCommit()
transactionRollback([savepoint])
transactionSetSavepoint([savepoint])
cfthread
To use the thread operation you specify a run action parameter. The thread runs the code in the operation body. A
thread block has the following general form:
23
The code in the thread operation body executes in a single ColdFusion thread. Code outside the body is not part of the
thread. You can use the following methods to manage the thread:
threadTerminate(threadName)
This function terminates the thread specified by the threadName parameter. It behaves in the same way as cfthread
action="terminate".
threadJoin([[threadName], timeout])
This function joins the current thread with the specified thread or threads. The current thread waits until either the
specified threads complete, or the timeout period passes, whichever happens first. The current thread inside a
thread function block belongs to that block thread and the current thread outside a thread function block is the page
thread.The threadName parameter is a comma-delimited list specifying one or more threads to join with the page
thread. If you omit this attribute, the current thread waits until all ColdFusion threads finish running.The timeout
parameter specifies the maximum time, in milliseconds, the calling thread waits for the other threads to complete
processing. If one or more threads do not complete before the time out period, the current thread processing begins
immediately. If you omit this attribute, the current thread waits until all specified threads finish running.
Note: You can also use these functions with transactions that you create by using cftransaction tags.
Service tags with bodies
ColdFusion provides objects, implemented as CFCs, that correspond to the following service tags:
cfftp
cfhttp
cfmail
cfpdf
cfquery
cfstoredproc
These tags have bodies and provide services such as executing queries or sending mail. Many of them have action
attributes, whereas others have an implicit action, such as execute. For each service tag, except for cfmail and cfpdf, a
component is returned with applicable properties set and you need to invoke getters on the properties to access the data.
Note: Previously, invoking getName() and getResult() methods returned data like query resultset, pdf object, or ftp prefix,
but now this has been changed and instead a component is returned with appropriate properties set.
The object names are the tag names without the cf prefix, for example, ftp. These objects also support child tag
functionality, such as cfmailpart and cfmailparam.
Note: There may be thread-safety issues if implicit setters are used and child tags such as cfmailpart or cfmailparam
are added because they get added into the CFC variable scope. It is therefore recommended that you create a new
component for each service. If you need to preserve the attribute state, use duplicate() on the component to retain any
initialized attribute values.
To use these tags in functions you:
1 Instantiate a service object.
2 Set object attributes and child tags
24
Note: Unlike the corresponding tags, you cannot use application-specific parameters in these functions. You can only use
the parameters that ColdFusion supports directly.
Step 1: Instantiate a service object
To create a function object, such as a mail object, use the new operator or createobject() function, as in the
following example:
myMail = new mail(server="sendmail.myCo.com");
As name=value parameters to the object initializer when you instantiate the object, as in the following example.
myMail = new mail(server="sendmail.myCo.com");
Note: You cannot use a getAttributeName function to get the value of the attribute specified by AttributeName.
Instead, use GetAttributes(AttributeName).
Note: If you specify a result attribute for a stored procedure, then calling getPrefix() returns,
executionTime,statusCode,cached . If you do not specify a result attribute, getPrefix() returns only
executionTime and statusCode.
Step 2b: Managing child tag operations
All service objects correspond to tags that have child tags. For example, cfmail has cfmailpart and cfmailparam
child tags.
To specify the child tag functionality, use the following methods:
httpObj.addParam
mailObj.addParam
mailObj.addPart
pdfObj.addParam
queryObj.addParam
storedProcObj.addParam
storedProcObj.addProcResult
For example:
25
mailObj.addparam(file="#ExpandPath('test.txt')#");
mailObj.addPart(name="foo",type="html",charset="utf-8",
body="This is a test message.");
You can also clear child tag settings by calling the following functions.
httpObj.clearParams
mailObj.clearParams
mailObj.clearParts
pdfObj.clearParams
queryObj.clearParams
storedProcObj.clearParams
storedProcObj.clearProcResults
If you used multiple add methods on an object, the clear method clears all values set in all the methods.
Step 3: Executing service actions
Service tags, excluding cfmail and cfpdf, have one or more actions that return results. Some, including the cfpdf and
cfftp tags have action attributes. For these tags, each action corresponds to a method on the service object. For example,
the ftp object action methods include open, close, listDir, getFile, rename, and many others. However, the way
service tags return data has changed. Now, a component is returned with applicable properties set and you need to
invoke getters on the properties to access the data.
Note: The PDF object has two action methods whose names differ from the corresponding cfftp action attribute values:
getPDFInfo and setPDFInfo instead of getInfo and setInfo. This difference is required to prevent name collisions
with the set and get methods for the PDF info attribute.
The cfhttp, cfmail, cfquery, and cfstoredproc tags do not have action attributes. Instead, the tags perform a
single action. To perform these actions in cfscript, call the following functions:
httpObj.send()
mailObj.send()
queryObj.execute()
storedProcObj.execute()
To get an action result, you typically assign the results of the action method to a variable, as in the following example:
Q = qry.execute(sql="select * from art");
Note: The attributes that specify you for an action are valid only for that action and are cleared once the action is
completed.
Service code example: mail, ftp, and http
The following example shows the use of the mail, http, and ftp services in cfscript.
26
27
getPrefix()
Returns the tag prefix cfftp, which is a struct, available after any cfftp operation
getResult()
getPrefix()
Returns the cfhttp prefix (struct) available after the tag has executed
getResult()
Applicable only if attributes like columns, delimiter, firstrowasheaders, name, or textQualifier are
specified, which direct ColdFusion to return a query object.
Query service example
<cfscript>
qryObj = new createObject("component","com.adobe.coldfuison.query").init();
<!---r here is no longer the query recordset but a component --->
r = qryObj.execute(sql="select * from art",
datasource="cfdocexamples",result="myresult",name="myquery");
<!---new way to access the data --->
resultset =r.getResult();
prefixData = r.getPrefix();
writedump(resultset);
writedump(prefixData);
<!---Using QoQ--->
qryObj.setAttributes(myquery=resultset);
r = qryObj.execute(sql="select * from myquery", dbtype="query");
writedump(r.getResult());
writedump(r.getPrefix());
</cfscript>
getPrefix()
Returns the result struct available after the query has executed.
getResult()
Returns the resultset returned by query (SELECT query) and throws an error for other types of SQL statements or
queries (like INSERT, UPDATE, DELETE).
PDF example
Whenever any action is performed for which a name attribute is specified, the new pdf is returned back to the user.
The following code shows typical actions on a PDF.
28
<cfscript>
pdfObj = new pdf();
x = pdfObj.read(source=#sourcefile#, name="PDFInfo");
x = pdfObj.processddx(ddxfile="#tocddx#",inputfiles="#inputStruct#",outputfiles=
"#outputStruct#",name="ddxVar");
x = pdfObj.addWatermark(source="#pdf1#",image="#image1#", pages="1",
overwrite="yes", name="test2");
x = pdfObj.removewatermark(source="#pdf1#", name="temp");
x = pdfObj.deletePages(source="#destfolder#dest.pdf",pages="2-4", name="deltest");
pdfObj.addparam(source="#pdf1#", pages="1-2,4");
pdfObj.merge(destination="#destfolder#merge-oneBigFile-5.pdf", overwrite="yes");
pdfObj.thumbnail(source="#pdf1#", overwrite="yes");
pdfObj.setInfo(source="#pdf1#", info="#{Author="Donald Duck"}#",
destination="#destfolder#pdfinfo.pdf", overwrite="yes");
pdfObj.write(source="myBook", destination="#destfolder#write1.pdf", version="1.4",
overwrite="yes");
pdfObj.protect(source="MyPdfVar", password="adobe", permissions="none",
newuserpassword="newuserpw", newownerpassword="newownerpw");
</cfscript>
Storedproc example
The following code shows sample usage of the storedproc service object.
<cfscript>
sp = new storedproc();
<!---add cfprocparam tags --->
sp.addParam(TYPE = "IN", CFSQLTYPE="CF_SQL_VARCHAR", VALUE="David",
DBVARNAME="@firstname");
sp.addParam(TYPE="IN", CFSQLTYPE="CF_SQL_VARCHAR", VALUE="Peterson",
DBVARNAME="@lastname", null ="yes");
sp.add Param(TYPE="OUT", CFSQLTYPE="CF_SQL_INTEGER", variable="MyCount",
DBVARN AME="@MyCount");
<!---add cfprocresult tags --->
sp.addProcResult(NAME = "home r", RESULTSET = 1);
sp.addProcResult( NAME = "home r2", RESULTSET = 2);
sp.addProcResult(NAME = "home r3", RESULTSET = 3) ;
<!---execute stored proc--->
r = sp.execute(procedure="sp_weird",datasource="some_dsn",result="r");
writedump(r.getProcResultSets());
<!---changed from sp.getProcResults()--->
writedump(r.getProcResultSets ("home r3"));
writedump(r.getPrefix());
<!---changed from sp.getResult()--->
writedump(r.getProcOutVariables());
<!---changed from sp.getProcVars()--->
</cfscript>
getPrefix()
Returns the cfstoredproc prefix (struct) available after the procedure has executed.
getProcResultsets()
getProcOutVariables()
29
Functions
Functions typically manipulate data and return a result. You can also create user-defined functions (UDFs), sometimes
referred to as custom functions.
Functions have the following general form:
functionName([argument1[, argument2]]...)
Some functions, such as the Now function take no arguments. Other functions require one or more comma-separated
arguments and can have additional optional arguments. All ColdFusion functions return a value. For example,
Round(3.14159) returns the value 3.
Built-in functions
ColdFusion built-in functions perform a variety of tasks, including, but not limited to, the following:
Creating and manipulating complex data variables, such as arrays, lists, and structures
Creating and manipulating queries
Creating, analyzing, manipulating, and formatting strings and date and time values
Evaluating the values of dynamic data
Determining the type of a variable value
Converting data between formats
Performing mathematical operations
Getting system information and resources
For alphabetical and categorized lists of ColdFusion functions, see ColdFusion Functions in the CFML Reference.
You use built-in functions throughout ColdFusion pages. Built-in functions are frequently used in a cfset or
cfoutput tag to prepare data for display or further use. For example, the following line displays todays date in the
format October 24, 2007:
<cfoutput>#DateFormat(Now(), "mmmm d, yyyy")#</cfoutput>
This code uses two nested functions. The Now function returns a ColdFusion date-time value representing the current
date and time. The DateFormat function takes the value returned by the Now function and converts it to the desired
string representation.
Functions are also valuable in CFScript scripts. ColdFusion does not support ColdFusion tags in CFScript, so you must
use functions to access ColdFusion functionality in scripts.
30
Features of properties with setter and getter methods include the following:
Component properties you assign with the set method are in the Variables scope that is private to the CFC. You
can get or reset the properties only by calling get or set methods.
If a property has a type attribute value, ColdFusion validates the data you pass to the setter function. The default
attribute has no effect on the property and does not set an initial property value.
A direct assignment statement, such as myCFC.MyProp=27 creates a standard This scope variable in the CFC, even
if you specify the property in a cfproperty tag. The This scope variable is independent of the properties that you
access using the set and get methods. In fact, you can have a This scope variable with the same name as a property
that you access using the set and get methods.
Use the cfproperty tag getter and setter attributes to control access to a property from outside the CFC:
A setter attribute value of true allows application code to set the property (the default behavior).
A false value specifies that the property can only be set from within the CFC. The getter attribute works similarly.
Explicit set or get methods override the implicit set and get methods. Therefore, if a CFC has a MyProp property
with an explicit setMyProp method, and you call the setMyProp() function in your application code, ColdFusion
uses your function and not an implicit function.
Validate and validateparams attributes
The validate attribute available with <cfproperty> takes the validator to be used for validating data when implicit
setter for this property is called. It takes the following validators:
string
boolean
integer
numeric
date
time
creditcard: A 13-16 digit number conforming to the mod10 algorithm.
email: A valid e-mail address.
eurodate: A date-time value. Any date part must be in the format dd/mm/yy. The format can use /, -, or . characters
as delimiters.
31
User-defined functions
You can write your own functions, user-defined functions (UDFs). You can use these functions in ColdFusion
expressions or in CFScript. You can call a user-defined function anywhere you can use a built-in CFML function. You
create UDFs using the cffunction tag or the cfscriptfunction statement. UDFs that you create using the
cffunction tag can include ColdFusion tags and functions. UDFs that you create in CFScript can only include
functions. You can create stand-alone UDFs or encapsulate them in a ColdFusion component.
User-defined functions let you encapsulate logic and operations that you use frequently in a single unit. This way, you
can write the code once and use it multiple times. UDFs ensure consistency of coding and enable you to structure your
CFML more efficiently.
Typical user-defined functions include mathematical routines, such as a function to calculate the logarithm of a
number; string manipulation routines, such as a function to convert a numeric monetary value to a string such as two
dollars and three cents; and can even include encryption and decryption routines.
Note: The Common Function Library Project at www.cflib.org includes a number of free libraries of user-defined
functions.
For more information on user-defined functions, see Writing and Calling User-Defined Functions on page 153.
ColdFusion components
ColdFusion components encapsulate multiple, related, functions. A ColdFusion component is essentially a set of
related user-defined functions and variables, with additional functionality to provide and control access to the
component contents. ColdFusion components can make their data private, so that it is available to all functions (also
called methods) in the component, but not to any application that uses the component.
ColdFusion components have the following features:
32
Constants
The value of a constant does not change during program execution. Constants are simple scalar values that you can use
within expressions and functions, such as Robert Trent Jones and 123.45. Constants can be integers, real numbers,
time and date values, Boolean values, or text strings. ColdFusion does not allow you to give names to constants.
Variables
Variables are the most frequently used operands in ColdFusion expressions. Variable values can be set and reset, and
can be passed as attributes to CFML tags. Variables can be passed as parameters to functions, and can replace most
constants.
ColdFusion has several built-in variables that provide information about the server and ColdFusion tags return. For a
list of the ColdFusion built-in variables, see Reserved Words and Variables in the CFML Reference.
The following two characteristics classify a variable:
The scope of the variable, which indicates where the information is available and how long the variable persists
The data type of the variable value, which indicates the type of information a variable represents, such as number,
string, or date
See Data types on page 32 for a list of data types (which also apply to constant values). For detailed information on
ColdFusion variables, including data types, scopes, and their use, see Using ColdFusion Variables on page 38.
Expressions
ColdFusion expressions consist of operands and operators. Operands are constants and variables, such as "Hello" or
MyVariable. Operators, such as the string concatenation operator (&) or the division operator (/) are the verbs that act
on the operands. ColdFusion functions also act as operators.
The simplest expression consists of a single operand with no operators. Complex expressions consist of multiple
operands and operators. For example, the following statements are all ColdFusion expressions:
12
MyVariable
(1 + 1)/2
"father" & "Mother"
Form.divisor/Form.dividend
Round(3.14159)
For detailed information on using variables, see Using ColdFusion Variables on page 38. For detailed information
on expressions and operators, see Using Expressions and Number Signs on page 64.
Data types
ColdFusion is considered typeless because you do not explicitly specify variable data types.
However, ColdFusion data, the constants and the data that variables represent, do have data types, which correspond
to the ways the data is stored on the computer.
ColdFusion data belongs to the following type categories:
33
Category
Simple
Represents one value. You can use simple data types directly in ColdFusion expressions. ColdFusion simple data
types are:
Complex
strings A sequence of alphanumeric characters enclosed in single or double quotation marks, such as This is
a test.
integers
Boolean values
date-time values ColdFusion supports a variety of data formats. For more information, see Date and time
formats on page 44.
Use True, Yes, or 1 for true and False, No, or 0 for false. Boolean values are not case sensitive.
A container for data. Complex variables generally represent more than one value. ColdFusion built-in complex
data types are:
arrays
structures
queries
Binary
Raw data, such as the contents of a GIF file or an executable program file
Object
COM, CORBA, Java, web services, and ColdFusion Component objects: Complex objects that you create and
access using the cfobject tag and other specialized tags.
Note: ColdFusion does not have a data type for unlimited precision decimal numbers, but it can represent such numbers
as strings and provides a function that supports unlimited precision decimal arithmetic. For more information, see
PrecisionEvaluate in the CFML Reference.
For more information on ColdFusion data types, see Using ColdFusion Variables on page 38.
Flow control
ColdFusion provides several tags that let you control how a page gets executed. These tags generally correspond to
programming language flow control statements, such as if, then, and else. The following tags provide ColdFusion flow
control:
Tags
Purpose
Select among sections of code based on the value of an expression. Case processing is not limited
to True and False conditions.
cfloop, cfbreak
Loop through code based on any of the following values: entries in a list, keys in a structure or
external object, entries in a query column, an index, or the value of a conditional expression.
cfabort, cfexit
CFScript also provides a set of flow-control statements. For information on using flow-control statements in CFScript,
see Extending ColdFusion Pages with CFML Scripting on page 106. For more details on using flow-control tags, see
the reference pages for these tags in the CFML Reference.
34
by the expression in the cfswitch tag, ColdFusion runs the code in the body of the cfcase tag and then exits the
cfswitch tag. If two cfcase tags have the same condition, ColdFusion generates an error.
3 If none of the cfcase tags match the value determined by the cfswitch tag, and the cfswitch tag body includes
a cfdefaultcase tag, ColdFusion runs the code in the cfdefaultcase tag body.
Note: Although the cfdefaultcase tag does not have to follow all cfcase tags, it is good programming practice to place
it at the end of the cfswitch statement.
The cfswitch tag provides better performance than a cfif tag with multiple cfelseif tags, and is easier to read. Switch
processing is commonly used when different actions are required based on a string variable such as a month or request
identifier.
The following example shows switch processing:
35
Description
Index
Loops through the body of the tag and increments a counter variable by a specified amount after each loop until
the counter reaches a specified value.
Conditional
Checks a condition and runs the body of the tag if the condition is True.
Query
Loops through the body of the tag once for each row in a query.
Loops through the body of the tag once for each entry in a list, each line in a file, or each item in an array.
Collection
Loops through the body of the tag once for each key in a ColdFusion structure or item in a COM/DCOM object.
The following example shows a simple conditional loop. The code does the following:
1 Sets up a ten-element array with the word kumquats in the fourth entry.
2 Loops through the array until it encounters an array element containing kumquats or it reaches the end of the
array.
3 Prints the value of the Boolean variable that indicates whether it found the word kumquats and the array index at
36
Note: You can get an infinite conditional loop if you do not force an end condition. In this example, the loop is infinite if
you omit the <cfset i = i + 1> statement. To end an infinite loop, stop the ColdFusion application server.
cfbreak
The cfbreak tag exits the cfloop tag. You typically use it in a cfif tag to exit the loop if a particular condition occurs.
The following example shows the use of a cfbreak tag in a query loop:
<cfloop query="fruitOrder">
<cfif fruit IS "kumquat">
<cfoutput>You cannot order kumquats!<br></cfoutput>
<cfbreak>
</cfif>
<cfoutput>You have ordered #quantity# #fruit#.<br></cfoutput>
</cfloop>
Character case
ColdFusion is not case sensitive. For example, the following all represent the cfset tag: cfset, CFSET, CFSet, and even
cfsEt. However, get in the habit of consistently using the same case rules in your programs; for example:
Develop consistent rules for case use, and stick to them. If you use lowercase characters for some tag names, use
them for all tag names.
Always use the same case for a variable. For example, do not use both myvariable and MyVariable to represent the
same variable on a page.
Follow these rules to prevent errors on application pages where you use both CFML and case-sensitive languages,
such as JavaScript.
37
Special characters
The double-quotation marks ("), single-quotation mark ('), and number sign (#) characters have special meaning to
ColdFusion. To include any of them in a string, double the character; for example, use ## to represent a single #
character.
The need to escape the single- and double-quotation marks is context sensitive. Inside a double-quoted string, you do
not need to escape single-quotation mark (apostrophe) characters. Inside a single-quoted string, you do not escape
double-quotation mark characters.
The following example illustrates escaping special characters, including the use of mixed single- and double-quotation
marks:
<cfset mystring = "We all said ""Happy birthday to you.""">
<cfset mystring2 = 'Then we said "How old are you now?"'>
<cfoutput>
#mystring#<br>
#mystring2#<br>
Here is a number sign: ##
</cfoutput>
Reserved words
As with any programming tool, you cannot use just any word or name for ColdFusion variables, UDFs and custom
tags. Avoid using any name that can be confused with a ColdFusion element. In some cases, if you use a word that
ColdFusion usesfor example, a built-in structure nameyou can overwrite the ColdFusion data.
The following list indicates words you must not use for ColdFusion variables, user-defined function names, or custom
tag names. While some of these words can be used safely in some situations, you can prevent errors by avoiding them
entirely. For a complete list of reserved words, see the CFML Reference.
Operators, such as NE or IS
The names of any built-in data structures, such as Error or File
The names of any built-in variables, such as RecordCount or CGI variable names
CFScript language element names such as for, default, or continue
Also, do not create form field names ending in any of the following, except to specify a form field validation rule using
a hidden form field name. (For more information on form field validation, see Introduction to Retrieving and
Formatting Data on page 703.)
_integer
_float
_range
38
_date
_time
_eurodate
Because ColdFusion is not case-sensitive, all of the following are reserved words: IS, Is, iS, and is.
CFScript
CFScript is a language within a language. CFScript is a scripting language that is similar to JavaScript but is simpler to
use. Also, unlike JavaScript, CFScript only runs on the ColdFusion server; it does not run on the client system. A
CFScript script can use all ColdFusion functions and all ColdFusion variables that are available in the scripts scope.
CFScript provides a compact and efficient way to write ColdFusion logic. Typical uses of CFScript include:
39
Creating variables
You create most ColdFusion variables by assigning them values. (You must use the ArrayNew function to create
arrays.) Most commonly, you create variables by using the cfset tag. You can also use the cfparam tag, and
assignment statements in CFScript. Tags that create data objects also create variables. For example, the cfquery tag
creates a query object variable.
ColdFusion automatically creates some variables that provide information about the results of certain tags or
operations. ColdFusion also automatically generates variables in certain scopes, such as Client and Server. For
information on these special variables, see Reserved Words and Variables in the CFML Reference and the
documentation of the CFML tags that create these variables.
ColdFusion generates an error when it tries to use a variable before it is created. This can happen, for example, when
processing data from an incompletely filled form. To prevent such errors, test for the variables existence before you
use it. For more information on testing for variable existence, see Ensuring variable existence on page 61.
For more information on how to create variables, see Creating and using variables in scopes on page 58.
A variable name must begin with a letter, underscore, or Unicode currency symbol.
The initial character can by followed by any number of letters, numbers, underscore characters, and Unicode
currency symbols.
Periods separate the components of structure or object names. They also separate a variable scope from the variable
name. You cannot use periods in simple variable names, with the exception of variables in the Cookie and Client
scopes. For more information on using periods, see Using periods in variable references on page 49.
The following rule applies to variable names, but does not apply to form field and argument names:
Prefix each variables name with its scope. Although some ColdFusion programmers do not use the Variables prefix
for local variable names, use prefixes for all other scopes. Using scope prefixes makes variable names clearer and
increases code efficiency. In many cases, you must prefix the scope. For more information, see About scopes on
page 56.
Note: In some cases, when you use an existing variable name, you must enclose it with number signs (#) to allow
ColdFusion to distinguish it from string or HTML text, and to insert its value, as opposed to its name. For more
information, see Using number signs on page 70.
40
Variable characteristics
You can classify a variable using the following characteristics:
The data type of the variable value, which indicates the kind of information a variable represents, such as number,
string, or date
The scope of the variable, which indicates where the information is available and how long the variable persists.
Data types
ColdFusion is often referred to as typeless because you do not assign types to variables and ColdFusion does not
associate a type with the variable name. However, the data that a variable represents does have a type, and the data type
affects how ColdFusion evaluates an expression or function argument. ColdFusion can automatically convert many
data types into others when it evaluates expressions. For simple data, such as numbers and strings, the data type is
unimportant until the variable is used in an expression or as a function argument.
ColdFusion variable data belongs to one of the following type categories:
Simple One value. Can use directly in ColdFusion expressions. Include numbers, strings, Boolean values, and date-
time values.
Binary Raw data, such as the contents of a GIF file or an executable program file.
Complex A container for data. Generally represent more than one value. ColdFusion built-in complex data types
include arrays, structures, queries, and XML document objects.
You cannot use a complex variable, such as an array, directly in a ColdFusion expression, but you can use simple data
type elements of a complex variable in an expression.
For example, with a one-dimensional array of numbers called myArray, you cannot use the expression myArray * 5.
However, you could use an expression myArray[3] * 5 to multiply the third element in the array by five.
Objects Complex constructs. Often encapsulate both data and functional operations. The following table lists the
types of objects that ColdFusion can use, and identifies the chapters that describe how to use them:
Object type
See
Java
ColdFusion component
Web service
41
ColdFusion provides the following functions for identifying the data type of a variable:
IsArray
IsBinary
IsBoolean
IsImage
IsNumericDate
IsObject
IsPDFObject
IsQuery
IsSimpleValue
IsStruct
IsXmlDoc
ColdFusion also includes the following functions for determining whether a string can be represented as or converted
to another data type:
IsDate
IsNumeric
IsXML
ColdFusion does not use a null data type. However, if ColdFusion receives a null value from an external source such
as a database, a Java object, or some other mechanism, it maintains the null value until you use it as a simple value. At
that time, ColdFusion converts the null to an empty string (""). Also, you can use the JavaCast function in a call to a
Java object to convert a ColdFusion empty string to a Java null.
Numbers
ColdFusion supports integers and real numbers. You can intermix integers and real numbers in expressions; for
example, 1.2 + 3 evaluates to 4.2.
Integers
ColdFusion supports integers between -2,147,483,648 and 2,147,483,647 (32-bit signed integers). You can assign a
value outside this range to a variable, but ColdFusion initially stores the number as a string. If you use it in an
arithmetic expression, ColdFusion converts it into a floating-point value, preserving its value, but losing precision as
the following example shows:
<cfset mybignum=12345678901234567890>
<cfset mybignumtimes10=(mybignum * 10)>
<cfoutput>mybignum is: #mybignum#</cfoutput><br>
<cfoutput>mybignumtimes10 is: #mybignumtimes10# </cfoutput><br>
42
Real numbers
Real numbers, numbers with a decimal part, are also known as floating point numbers. ColdFusion real numbers can
range from approximately -10300 to approximately 10300. A real number can have up to 12 significant digits. As with
integers, you can assign a variable a value with more digits, but the data is stored as a string. The string is converted to
a real number, and can lose precision, when you use it in an arithmetic expression.
You can represent real numbers in scientific notation. This format is xEy, where x is a positive or negative real number
in the range 1.0 (inclusive) to 10 (exclusive), and y is an integer. The value of a number in scientific notation is x times
10y. For example, 4.0E2 is 4.0 times 102, which equals 400. Similarly, 2.5E-2 is 2.5 times 10-2, which equals 0.025.
Scientific notation is useful for writing very large and very small numbers.
BigDecimal numbers
ColdFusion does not have a special BigDecimal data type for arbitrary length decimal numbers such as
1234567890987564.234678503059281. Instead, it represents such numbers as strings. ColdFusion does, however, have
a PrecisionEvaluate function that can take an arithmetic expression that uses BigDecimal values, calculate the
expression, and return a string with the resulting BigDecimal value. For more information, see PrecisionEvaluate in
the CFML Reference.
Strings
In ColdFusion, text values are stored in strings. You specify strings by enclosing them in either single- or doublequotation marks. For example, the following two strings are equivalent:
"This is a string"
'This is a string'
You can write an empty string in the following ways:
To include a double-quotation mark in a double-quoted string, use two double-quotation marks (known as escaping
the double-quotation mark). The following example uses escaped double-quotation marks:
<cfset myString="This is a single-quotation mark: ' This is a double-quotation mark: """>
<cfoutput>#mystring#</cfoutput><br>
Because strings can be in either double-quotation marks or single-quotation marks, both of the preceding examples
display the same text:
This is a single-quotation mark: ' This is a double-quotation mark: "
To insert a number sign (#) in a string, you must escape the number sign, as follows:
43
Lists
ColdFusion includes functions that operate on lists, but it does not have a list data type. In ColdFusion, a list is just a
string that consists of multiple entries separated by delimiter characters.
The default delimiter for lists is the comma. If you use any other character to separate list elements, you must specify
the delimiter in the list function. You can also specify multiple delimiter characters. For example, you can tell
ColdFusion to interpret a comma or a semicolon as a delimiter, as the following example shows:
<cfset MyList="1,2;3,4;5">
<cfoutput>
List length using ; and , as delimiters: #listlen(Mylist, ";,")#<br>
List length using only , as a delimiter: #listlen(Mylist)#<br>
</cfoutput>
Boolean values
A Boolean value represents whether something is true or false. ColdFusion has two special constantsTrue and
Falseto represent these values. For example, the Boolean expression 1 IS 1 evaluates to True. The expression
"Monkey" CONTAINS "Money" evaluates to False.
You can use Boolean constants directly in expressions, as in the following example:
<cfset UserHasBeenHere = True>
In Boolean expressions, True, nonzero numbers, and the strings Yes, 1, True are equivalent; and False, 0, and the
strings No, 0, and False are equivalent.
Boolean evaluation is not case sensitive. For example, True, TRUE, and true are equivalent.
Date-Time values
ColdFusion can perform operations on date and time values. Date-time values identify a date and time in the range
100 AD to 9999 AD. Although you can specify just a date or a time, ColdFusion uses one data type representation,
called a date-time object, for date, time, and date and time values.
ColdFusion provides many functions to create and manipulate date-time values and to return all or part of the value
in several different formats.
You can enter date and time values directly in a cfset tag with a constant, as follows:
<cfset myDate = "October 30, 2001">
44
When you do this, ColdFusion stores the information as a string. If you use a date-time function, ColdFusion stores
the value as a date-time object, which is a separate simple data type. When possible, use date-time functions such as
CreateDate and CreateTime to specify dates and times, because these functions can prevent you from specifying the
date or time in an invalid format and they create a date-time object immediately.
Date and time formats
You can directly enter a date, time, or date and time, using standard U.S. date formats. ColdFusion processes the twodigit-year values 0 to 29 as twenty-first century dates; it processes the two-digit-year values 30 to 99 as twentieth
century dates. Time values can include units down to seconds. The following table lists valid date and time formats:
To specify
Date
Time
02:34:12
2:34a
2:34am
02:34am
2am
45
Format
Base64
Encodes the binary data in the lowest six bits of each byte. It ensures that binary data and non-ANSI character data
can be transmitted using e-mail without corruption. The Base64 algorithm is specified by IETF RFC 2045, at
www.ietf.org/rfc/rfc2045.txt.
Hex
Uses two characters in the range 0-9 and A-F represent the hexadecimal value of each byte; for example, 3A.
UU
ColdFusion provides the following functions that convert among string data, binary data, and string encoded binary
data:
Function
Description
BinaryDecode
BinaryEncode
CharsetDecode
CharsetEncode
ToBase64
ToBinary
Converts Base64 encoded data to binary data. The BinaryDecode function provides a superset of the ToBase64
functionality.
ToString
Converts most simple data types to string data. It can convert numbers, date-time objects, and Boolean values. (It
converts date-time objects to ODBC timestamp strings.) Adobe recommends that you use the CharsetEncode
function to convert binary data to a string in new applications.
46
Arrays
Arrays are a way of storing multiple values in a table-like format that can have one or more dimensions. You create
arrays using a function or an assignment statement:
The ColdFusion ArrayNew function creates an array and specifies its initial dimensions. For example, the following
line creates an empty two-dimensional array:
<cfset myarray=ArrayNew(2)>
A direct assignment creates an array and populates an array element. For example, the following line creates a twodimensional array and sets the value of row 1 column 2 to the current date.
<cfset myarray[1][2]=Now()>
You reference elements using numeric indexes, with one index for each dimension, as shown in the preceding
example.
You can create arrays with up to three dimensions directly. However, there is no limit on array size or maximum
dimension. To create arrays with more than three dimensions, create arrays of arrays.
After you create an array, you can use functions or direct references to manipulate its contents.
When you assign an existing array to a new variable, ColdFusion creates a new array and copies the old arrays contents
to the new array. The following example creates a copy of the original array:
<cfset newArray=myArray>
For more information on using arrays, see Using Arrays and Structures on page 82.
Structures
ColdFusion structures consist of key-value pairs, where the keys are text strings and the values can be any ColdFusion
data type, including other structures. Structures let you build a collection of related variables that are grouped under a
single name. To create a structure, use the ColdFusion StructNew function. For example, the following line creates a
new, empty, structure called depts:
<cfset depts=StructNew()>
You can also create a structure by assigning a value in the structure. For example, the following line creates a new
structure called MyStruct with a key named MyValue, equal to 2:
<cfset MyStruct.MyValue=2>
Note: In ColdFusion versions through ColdFusion 7, this line created a Variables scope variable named
"MyStruct.MyValue" with the value 2.
After you create a structure, you can use functions or direct references to manipulate its contents, including adding
key-value pairs.
You can use either of the following methods to reference elements stored in a structure:
StructureName.KeyName
StructureName["KeyName"]
The following examples show these methods:
depts.John="Sales"
depts["John"]="Sales"
When you assign an existing structure to a new variable, ColdFusion does not create a new structure. Instead, the new
variable accesses the same data (location) in memory as the original structure variable. In other words, both variables
are references to the same object.
47
For example, the following line creates a new variable, myStructure2, that is a reference to the same structure as the
myStructure variable:
<cfset myStructure2=myStructure>
When you change the contents of myStructure2, you also change the contents of myStructure. To copy the contents
of a structure, use the ColdFusion Duplicate function, which copies the contents of structures and other complex
data types.
Structure key names can be the names of complex data objects, including structures or arrays. This lets you create
arbitrarily complex structures.
For more information on using structures, see Using Arrays and Structures on page 82.
Queries
A query object, sometimes referred to as a query, query result, or recordset, is a complex ColdFusion data type that
represents data in a set of named columns, like the columns of a database table. Many tags can return data as a query
object, including the following:
cfquery
cfdirectory
cfhttp
cfldap
cfpop
cfprocresult
In these tags, the name attribute specifies the query objects variable name. The QueryNew function also creates query
objects.
When you assign a query to a new variable, ColdFusion does not copy the query object. Instead, both names point to
the same recordset data. For example, the following line creates a new variable, myQuery2, that references the same
recordset as the myQuery variable:
<cfset myQuery2 = myQuery>
If you make changes to data in myQuery, myQuery2 also shows those changes.
You reference query columns by specifying the query name, a period, and the column name; for example:
myQuery.Dept_ID
When you reference query columns inside tags, such as cfoutput and cfloop, in which you specify the query name
in a tag attribute, you do not have to specify the query name.
You can access query columns as if they are one-dimensional arrays. For example, the following line assigns the
contents of the Employee column in the second row of the myQuery query to the variable myVar:
<cfset myVar = myQuery.Employee[2]>
Note: You cannot use array notation to reference a row (of all columns) of a query. For example, myQuery[2] does not
reference the second row of the myQuery query object.
Working with structures and queries
Because structure variables and query variables are references to objects, the rules in the following sections apply to
both types of data.
48
To clear the server scope query variable, reassign the query object, as follows:
<cfset Server.SScopeQuery = 0>
This line deletes the reference to the object from the server scope, but does not remove any other references that can
exist.
To reference elements in a query column, use the row number as an array index. For example, both of the following
lines display the word "ben":
<cfoutput> #myQuery.Firstname[1]# </cfoutput><br>
<cfoutput> #myQuery["Firstname"][1]# </cfoutput><br>
49
ColdFusion behavior is less straightforward, however, when you use the query column references myQuery.Firstname
and myQuery["Firstname"] without using an array index. The two reference formats produce different results.
If you reference myQuery.Firstname, ColdFusion automatically converts it to the first row in the column. For example,
the following lines print the word "ben":
<cfset myCol = myQuery.Firstname >
<cfoutput>#mycol#</cfoutput>
If you reference Query["Firstname"], ColdFusion does not automatically convert it to the first row of the column.
For example, the following line results in an error message indicating that ColdFusion cannot convert a complex type
to a simple value:
<cfoutput> #myQuery['Firstname']# </cfoutput><br>
Similarly, the following lines print the name "marjorie", the value of the second row in the column:
<cfset myCol = myQuery["Firstname"]>
<cfoutput>#mycol[2]#</cfoutput><br>
However, when you make an assignment that requires a simple value, ColdFusion automatically converts the query
column to the value of the first row. For example, the following lines display the name "ben" twice:
<cfoutput> #myQuery.Firstname# </cfoutput><br>
<cfset myVar= myQuery['Firstname']>
<cfoutput> #myVar# </cfoutput><br>
If myVar is not the name of a complex object, checks whether myVar.a is the name of a complex object and skips
step 3.
50
value of b.
If myVar is a complex object but a is not a complex object, checks whether a.b is the name of a simple variable and
returns its value.
If myVar.a is not a complex object, checks whether myVar.a.b is the name of a simple variable and returns its value.
This way, ColdFusion correctly resolves the variable name and can get its value.
You can also use array notation to get a simple variable with a name that includes periods. In this form of array
notation, you use the scope name (or the complex variable that contains the simple variable) as the array name. You
place the simple variable name, in single- or double-quotation marks, inside the brackets.
Using array notation is more efficient than using plain dot notation because ColdFusion does not have to analyze and
look up all the possible key combinations. For example, both of the following lines write the value of myVar.a.b, but
the second line is more efficient than the first:
<cfoutput>myVar.a.b is: #myVar.a.b#<br></cfoutput>
<cfoutput>myVar.a.b is: #Variables["myVar.a.b"]#<br></cfoutput>
Setting a variable
ColdFusion cannot be as flexible when it sets a variable value as when it gets a variable, because it must determine the
type of variable to create or set. Therefore, the rules for variable names that you set are stricter. Also, the rules vary
depending on whether the first part of the variable name is the Cookie or Client scope identifier.
For example, assume that you have the following code:
<cfset myVar.a.b = "This is a test">
If either myVar or myVar.a exist and neither one is a structure, ColdFusion generates an error.
In other words, ColdFusion uses the same rules as for getting a variable to resolve the variable name until it finds a
name that does not exist yet. It then creates any structures that are needed to create a key named b inside a structure,
and assigns the value to the key.
However, if the name before the first period is either Cookie or Client, ColdFusion uses a different rule. It treats all the
text (including any periods) that follow the scope name as the name of a simple variable, because Cookie and Client
scope variables must be simple. If you have the following code, you see that ColdFusion creates a single, simple Client
scope variable named myVar.a.b:
<cfset Client.myVar.a.b = "This is a test">
<cfdump var=#Client.myVar.a.b#>
51
Reference the variable as part of a structure. You can always do this, because ColdFusion considers all scopes to be
structures. For more information on scopes, see About scopes on page 56.
Place the variable name that must include a period inside brackets and single- or double-quotation marks.
The following example shows this technique:
<cfset Variables['My.Variable.With.Periods'] = 12>
<cfset Request["Another.Variable.With.Periods"] = "Test variable">
<cfoutput>
My.Variable.With.Periods is: #My.Variable.With.Periods#<br>
Request.Another.Variable.With.Periods is:
#Request.Another.Variable.With.Periods#<br>
</cfoutput>
Operation-driven evaluation
Conventional programming languages enforce strict rules about mixing objects of different types in expressions. For
example, in a language such as C++ or Basic, the expression ("8" * 10) produces an error because the multiplication
operator requires two numeric operands and "8" is a string. When you program in such languages, you must convert
between data types to ensure error-free program execution. For example, the previous expression might have to be
written as (ToNumber("8") * 10).
In ColdFusion, however, the expression ("8" * 10) evaluates to the number 80 without generating an error. When
ColdFusion processes the multiplication operator, it automatically attempts to convert its operands to numbers. Since
"8" can be successfully converted to the number 8, the expression evaluates to 80.
52
requires numeric operands and the CONTAINS operator requires string operands.)
For functions, it determines the type required for each function argument. (For example, the Min function requires
two numbers as arguments and the Len function requires a string.)
2 It evaluates all operands or function arguments.
3 It converts all operands or arguments whose types differ from the required type. If a conversion fails, it reports an
error.
As Boolean
As number
As date-time
As string
"Yes"
True
Error
"Yes"
"No"
False
Error
"No"
True
True
Error
"Yes"
False
False
Error
"No"
Number
Number
String
If "Yes", True
Date
Error
Date
An ODBC timestamp.
ColdFusion cannot convert complex types, such as arrays, queries, and COM objects, to other types. However, it can
convert simple data elements of complex types to other simple data types.
Type conversion considerations
The following sections detail specific rules and considerations for converting between types.
53
54
However, if myVariable has a numeric value such as 12, only the first example produces a result. In the second case,
the value of myVariable is not converted to a Boolean data type, because the IS operator does not require a specific data
type and just tests the two values for identity. Therefore, ColdFusion compares the value 12 with the constant True.
The two are not equal, so nothing is printed. If myVariable is 1, "Yes", or True, however, both examples print the same
result, because ColdFusion considers these to be identical to Boolean True.
If you use the following code, the output statement does display, because the value of the variable, 12, is not equal to
the Boolean value False:
<cfif myVariable IS NOT False>
<cfoutput>myVariable equals #myVariable# and IS NOT False
</cfoutput>
</cfif>
As a result, use the test <cfif testvariable>, and not use the IS comparison operator when testing whether a variable
is True or False. This issue is a case of the more general problem of ambiguous type expression evaluation, described
in the following section.
Ambiguous type expressions and strings
When ColdFusion evaluates an expression that does not require strings, including all comparison operations, such as
IS or GT, it checks whether it can convert each string value to a number or date-time object. If so, ColdFusion converts
it to the corresponding number or date-time value (which is stored as a number). It then uses the number in the
expression.
Short strings, such as 1a and 2P, can produce unexpected results. ColdFusion can interpret a single "a" as AM and a
single "P" as PM. This can cause ColdFusion to interpret strings as date-time values in cases where this was not
intended.
Similarly, if the strings can be interpreted as numbers, you can get unexpected results.
For example, ColdFusion interprets the following expressions as shown:
Expression
Interpretation
If 1:00am is 1:00am.
<cfset age="4a">
Treat the variable age as 4:00 am, convert it to the date-time value 0.16666666667, and add 7 to
make it 7.16666666667.
If 0 is 0.
To prevent such ambiguities when you compare strings, use the ColdFusion string comparison functions Compare and
CompareNoCase, instead of the comparison operators.
55
You can also use the IsDate function to determine whether a string can be interpreted as a date-time value, or to add
characters to a string before comparison to avoid incorrect interpretation.
Date-time functions and queries when ODBC is not supported
Many CFML functions, including the Now, CreateDate, CreateTime, and CreateDateTime functions, return datetime objects. ColdFusion creates Open Database Connectivity (ODBC) timestamp values when it converts date-time
objects to strings. As a result, you can get unexpected results when using dates with a database driver that does not
support ODBC escape sequences, or when you use SQL in a query of queries.
If you use SQL to insert data into a database or in a WHERE clause to select data from a database, and the database
driver does not support ODBC-formatted dates, use the DateFormat function to convert the date-time value to a valid
format for the driver. This rule also applies to queries of queries.
For example, the following SQL statement uses the DateFormat function in a query of queries to select rows that have
MyDate values in the future:
<cfquery name="MyQofQQ" dbtype="query">
SELECT *
FROM DateQuery
WHERE MyDate >= '#DateFormat(Now())#'
</cfquery>
The following query of queries fails with the error message Error: {ts is not a valid date, because the ColdFusion Now
function returns an ODBC timestamp:
<cfquery name="MyQofQQ" dbtype="query">
SELECT *
FROM DateQuery
WHERE MyDate >= '#now()#'
</cfquery>
The JavaCast function takes two parameters: a string representing the Java data type and the variable whose type you
are setting. You can specify the following Java data types: Boolean, int, long, float, double, and String.
For more information on the JavaCast function, see the CFML Reference.
Using quotation marks
To ensure that ColdFusion properly interprets string data, surround strings in single- or double-quotation marks. For
example, ColdFusion evaluates 10/2/2001 as a string that can be converted into a date-time object. However, it
evaluates 10/2/2001 as a mathematical expression, 5/2001, which evaluates to 0.00249875062469.
56
Example 1
2 * True + "YES" - ('y' & "es")
About scopes
Variables differ in how they are set (by your code or by ColdFusion), the places in your code where they are
meaningful, and how long their values persist. These considerations are generally referred to as a variables scope.
Commonly used scopes include the Variables scope, the default scope for variables that you create, and the Request
scope, which is available for the duration of an HTTP request.
Note: User-defined functions also belong to scopes. For more information, see Specifying the scope of a function on
page 173.
Scope types
The following table describes ColdFusion scopes:
Scope
Description
Application
Contains variables that are associated with one, named application on a server. The cfapplication tag name
attribute or the Application.cfc This.name variable setting specifies the application name. For more information,
see Using Persistent Data and Locking on page 301.
Arguments
Variables passed in a call to a user-defined function or ColdFusion component method. For more information, see
About the Arguments scope on page 161.
Attributes
Used only in custom tag pages and threads. Contains the values passed by the calling page or cfthread tag in
the tags attributes. For more information, see Creating and Using Custom CFML Tags on page 208 and Using
ColdFusion Threads on page 328.
Caller
Used only in custom tag pages. The custom tags Caller scope is a reference to the calling pages Variables scope.
Any variables that you create or change in the custom tag page using the Caller scope are visible in the calling
pages Variables scope. For more information, see Creating and Using Custom CFML Tags on page 208.
CGI
Contains environment variables identifying the context in which a page was requested. The variables available
depend on the browser and server software. For a list of the commonly used CGI variables, see Reserved Words
and Variables in the CFML Reference.
57
Scope
Description
Client
Contains variables that are associated with one client. Client variables let you maintain state as a user moves from
page to page in an application, and are available across browser sessions. By default, Client variables are stored in
the system registry, but you can store them in a cookie or a database. Client variables cannot be complex data
types and can include periods in their names. For more information, see Using Persistent Data and Locking on
page 301.
Cookie
Contains variables maintained in a users browser as cookies. Cookies are typically stored in a file on the browser,
so they are available across browser sessions and applications. You can create memory-only Cookie variables,
which are not available after the user closes the browser. Cookie scope variable names can include periods.
Flash
Variables sent by a SWF movie to ColdFusion and returned by ColdFusion to the movie. For more information, see
Using the Flash Remoting Service on page 606.
Form
Contains variables passed from a Form page to its action page as the result of submitting the form. (If you use the
HTML form tag, you must use method="post".) For more information, see Introduction to Retrieving and
Formatting Data on page 703.
Contains variables that are declared inside a user-defined function or ColdFusion component method and exist
only while a function executes. For more information, see Writing and Calling User-Defined Functions on
page 153.
Request
Used to hold data that must be available for the duration of one HTTP request. The Request scope is available to
all pages, including custom tags and nested custom tags, that are processed in response to the request.
This scope is useful for nested (child/parent) tags. This scope can often be used in place of the Application scope,
to avoid the need for locking variables. Several chapters discuss using the Request scope.
Server
Contains variables that are associated with the current ColdFusion server. This scope lets you define variables that
are available to all your ColdFusion pages, across multiple applications. For more information, see Using
Persistent Data and Locking on page 301.
Session
Contains variables that are associated with one client and persist only as long as the client maintains a session.
They are stored in the servers memory and can be set to time out after a period of inactivity. For more information,
see Using Persistent Data and Locking on page 301.
This
Exists only in ColdFusion components or cffunction tags that are part of a containing object such as a
ColdFusion Struct. Exists for the duration of the component instance or containing object. Data in the This scope
is accessible from outside the component or container by using the instance or object name as a prefix.
ThisTag
Used only in custom tag pages. The ThisTag scope is active for the current invocation of the tag. If a custom tag
contains a nested tag, any ThisTag scope values you set before calling the nested tag are preserved when the
nested tag returns to the calling tag.
The ThisTag scope includes three built-in variables that identify the tags execution mode, contain the tags
generated contents, and indicate whether the tag has an end tag.
A nested custom tag can use the cfassociate tag to return values to the calling tags ThisTag scope. For more
information, see Accessing tag instance data on page 216.
Thread
Variables that are created and changed inside a ColdFusion thread, but can be read by all code on the page that
creates the thread. Each thread has a Thread scope that is a subscope of a cfthread scope. For more information,
see Using ColdFusion Threads on page 328.
58
Scope
Description
thread local
Variables that are available only within a ColdFusion thread. For more information, see Using ColdFusion
Threads on page 328.
URL
Contains parameters passed to the current page in the URL that is used to call it. The parameters are appended to
the URL in the format ?variablename = value[&variablename=value...]; for example
www.MyCompany.com/inputpage.cfm?productCode=A12CD1510&quantity=3.
If a URL includes multiple parameters with the same name, the resulting variable in the ColdFusion URL scope
consists of all parameter values separated by commas. For example, a URL of the form
http://localhost/urlparamtest.cfm? param=1¶m=2¶m=3 results in a URL.param variable value of 1,2,3
on the ColdFusion page.
Variables
The default scope for variables of any type that are created with the cfset and cfparam tags. A Variables scope
variable is available only on the page on which it is created and any included pages (see also the Caller scope).
Variables scope variables created in a CFC are available only to the component and its functions, and not to the
page that instantiates the component or calls its functions.
Important: To prevent data corruption, you lock code that uses Session, Application, or Server scope variables. For more
information, see Using Persistent Data and Locking on page 301.
Prefix required to
reference
Where available
Created by
Application
Yes
Arguments
No
Attributes
Yes
(type)
On the calling page, On the page that calls the custom tag, as local
No (Variables prefix variables (Variables scope).
is optional).
Cffile
Yes
A cffile tag.
CGI
No
Client
No
Cookie
No
59
Scope prefix
Prefix required to
reference
Where available
Created by
Flash
Yes
Form
No
On the action page of a form and in custom tags A form or cfform tag. Contains the values of
called by the action page; cannot be used on a
form field tags (such as input) in the form body
form page that is not also the action page.
when the form is submitted. The variable name
is the name of the form field.
Local
No
(type)
Request
Yes
Server
Yes
To any page on the ColdFusion server. Surround Specifying the prefix Server when you create the
all code that uses server variables in cflock
variable.
blocks.
Session
Yes
This
Yes
ThisTag
Yes
Thread
60
Scope prefix
Prefix required to
reference
Where available
Created by
thread-local (no
prefix)
none
URL
No
Variables
No
(type)
(Local)
Using scopes
The following sections provide details on how you can create and use variables in different scopes.
Evaluating unscoped variables
If you use a variable name without a scope prefix, ColdFusion checks the scopes in the following order to find the
variable:
1 Local (function-local, UDFs and CFCs only)
2 Arguments
3 Thread local (inside threads only)
4 Query (not a true scope; variables in query loops)
5 Thread
6 Variables
7 CGI
8 Cffile
9 URL
10 Form
11 Cookie
12 Client
Because ColdFusion must search for variables when you do not specify the scope, you can improve performance by
specifying the scope for all variables.
To access variables in all other scopes, you must prefix the variable name with the scope identifier.
Scopes and CFX tags
ColdFusion scopes do not apply to ColdFusion Extension (CFX) tags, custom tags that you write in a programming
language such as C++ or Java. The ColdFusion page that calls a CFX tag must use tag attributes to pass data to the CFX
tag. The CFX tag must use the Java Request and Response interfaces or the C++ Request class to get and return data.
61
The Java setVariable Response interface method and C++ CCFX::SetVariable method return data to the
Variables scope of the calling page. Therefore, they are equivalent to setting a Caller scope variable in a custom
ColdFusion tag.
Using scopes as structures
ColdFusion makes all named scopes available as structures. You cannot access the function-local scope for userdefined functions (UDFs) that you define using CFScript as a structure.
You can reference the variables in named scopes as elements of a structure. To do so, specify the scope name as the
structure name and the variable name as the key. For example, if you have a MyVar variable in the Request scope, you
can reference it in either of the following ways:
Request.MyVar
Request["MyVar"]
Similarly, you can use CFML structure functions to manipulate the contents of the scope. For more information on
using structures, see Using Arrays and Structures on page 82.
Important: Do not call StructClear(Session) to clear session variables. This deletes the SessionID, CFID, and
CFtoken built-in variables, effectively ending the session. If you want to use StructClear to delete your application
variables, place those variables in a structure in the Session scope, and then clear that structure. For example, place all
your application variables in Session.MyVars and then call StructClear(Session.MyVars) to clear the variables.
You can use the IsDefined function to test for the variables existence.
You can use the cfparam tag to test for a variable and set it to a default value if it does not exist.
You can use a cfinput tag with a hidden attribute to tell ColdFusion to display a helpful message to any user who
does not enter data in a required field. For more information on this technique, see Requiring users to enter values
in form fields on page 709.
You must always enclose the argument passed to the IsDefined function in quotation marks. For more information
on the IsDefined function, see the CFML Reference.
62
To test whether an element exists in an array before you display its value, use a format such as the following:
</cfoutput>
<cfloop index="i" from="1" to="#Arraylen(myArray)#">
<cfif ArrayIsDefined(myArray, i)>
#i#: #myArray[i]#<br>
</cfif>
</cfloop>
</cfoutput>
Notice that in the ArrayIsDefined function, unlike the IsDefined function, you do not surround the variable name
in quotation marks.
If you attempt to evaluate a variable that you did not define, ColdFusion cannot process the page and displays an error
message. To help diagnose such problems, turn on debugging in the ColdFusion Administrator or use the debugger
in your editor. The Administrator debugging information shows which variables are being passed to your application
pages.
Variable existence considerations
If a variable is part of a scope that is available as a structure, you might get a minor performance increase by testing the
variables existence using the StructKeyExists function instead of the IsDefined function.
You can also determine which Form variables exist by inspecting the contents of the Form.fieldnames built-in
variable. This variable contains a list of all the fields submitted by the form. Remember, however, that form text fields
are always submitted to the action page, and can contain an empty string if the user did not enter data.
Note: For information on using the type attribute to validate the parameter data type, see the CFML Reference.
There are two ways to use the cfparam tag to test for variable existence, depending on how you want the validation
test to proceed:
With only the name attribute to test that a required variable exists. If it does not exist, the ColdFusion server stops
processing the page and displays an error message.
With the name and default attributes to test for the existence of an optional variable. If the variable exists,
processing continues and the value is not changed. If the variable does not exist, it is created and set to the value of
the default attribute, and processing continues.
The following example shows how to use the cfparam tag to check for the existence of an optional variable and to set
a default value if the variable does not already exist:
<cfparam name="Form.Contract" default="Yes">
63
For example, the following cfparam tags indicate that this page expects two form variables named StartRow and
RowsToFetch:
<cfparam name="Form.StartRow">
<cfparam name="Form.RowsToFetch">
If the page with these tags is called without either one of the form variables, an error occurs and the page stops
processing. By default, ColdFusion displays an error message; you can also handle the error as described in Handling
Errors on page 275.
Example: setting default values
The following example uses the cfparam tag to see if optional variables exist. If they do exist, processing continues. If
they do not exist, the ColdFusion server creates them and sets them to the default values.
<cfparam name="Cookie.SearchString" default="temple">
<cfparam name="Client.Color" default="Gray">
<cfparam name="ShowExtraInfo" default="No">
You can use the cfparam tag to set default values for URL and Form variables, instead of using conditional logic. For
example, you could include the following code on the action page to ensure that a SelectedDepts variable exists:
<cfparam name="Form.SelectedDepts" default="Marketing,Sales">
Validating data
It is often not sufficient that input data merely exists; it must also have the right format. For example, a date field must
have data in a date format. A salary field must have data in a numeric or currency format. There are many ways to
ensure the validity of data, including the following methods:
Use the cfparam tag with the type attribute to validate a variable.
Use the IsValid function to validate a variable.
Use the cfqueryparam tag in a SQL WHERE clause to validate query parameters.
Use cfform controls that have validation attributes.
Use a form input tag with a hidden attribute to validate the contents of a form input field.
Note: Data validation using the cfparam,cfqueryparam, and form tags is done by the server. Validation using cfform
tags and hidden fields is done using JavaScript in the users browser, before any data is sent to the server.
For detailed information on validating data in forms and variables, see Validating Data on page 743 For detailed
information on validating query parameters, see Using cfqueryparam on page 416.
Simple variables and arrays are passed as copies of the data. If your argument is an expression that contains multiple
simple variables, the result of the expression evaluation is copied to the function or tag.
64
Structures, queries, and cfobject objects are passed as references to the object.
If the tag or function gets a copy of the calling pages data, changes to the variable in the custom tag or function do not
change the value of the variable on the calling page. If the variable is passed by reference, changes to the variable in the
custom tag or function also change the value of the variable in the calling page.
To pass a variable to a custom tag, you must enclose the variable name in number signs. To pass a variable to a function,
do not enclose the variable name in number signs. For example, the following code calls a user-defined function using
three Form variables:
<cfoutput>
TOTAL INTEREST: #TotalInterest(Form.Principal, Form.AnnualPercent,Form.Months)#<br>
</cfoutput>
The following example calls a custom tag using two variables, MyString and MyArray:
<cf_testTag stringval=#MyString# arrayval=#MyArray#>
Expressions
ColdFusion expressions consist of operands and operators. Constants and variables are operands. Operators, such as
the multiplication sign, are the verbs that act on the operands; functions are a form of operator.
The simplest expression consists of a single operand with no operators. Complex expressions have multiple operators
and operands. The following are all ColdFusion expressions:
12
MyVariable
a++
(1 + 1)/2
"father" & "Mother"
Form.divisor/Form.dividend
Round(3.14159)
Operators act on the operands. Some operators, such as functions with a single argument, take a single operand. Many
operators, including most arithmetic and logical operators, take two operands. The following is the general form of a
two-operand expression:
Expression Operator Expression
Expressions surround the operator. Each expression can be a simple operand (variable or constant) or a subexpression
consisting of more operators and expressions. Complex expressions are built up using subexpressions. For example,
in the expression (1 + 1)/2, 1 + 1 is a subexpression consisting of an operator and two operands.
65
Operator types
ColdFusion has Five types of operators:
Arithmetic
Boolean
Decision (or comparison)
String
Ternary
Functions also can be viewed as operators because they act on operands.
Arithmetic operators
The following table describes the arithmetic operators:
Operator
Description
+-*/
++ --
+= -= *= /= %=
Compound assignment operators. The variable on the right is used as both an element in the expression and the
result variable. Thus, the expression a += b is equivalent to a = a +b.
An expression can have only one compound assignment operator.
+-
MOD
Modulus: Return the remainder after a number is divided by a divisor. The result has the same sign as the divisor.
The value to the right of the operator should be an integer; using a non-numeric value causes an error, and if you
specify a real number, ColdFusion ignores the fractional part (for example, 11 MOD 4.7 is 3).
or %
\
Integer division: Divide an integer by another integer. The result is also an integer; for example, 9\4 is 2. The right
operand cannot be zero.
Exponentiation: Return the result of a number raised to a power (exponent). Use the caret character (^) to
separate the number from the power; for example, 2^3 is 8. Real and negative numbers are allowed for both the
base and the exponent. However, any expression that equates to an imaginary number, such -1^.5 results in the
string "-1.#IND. ColdFusion does not support imaginary or complex numbers.
Boolean operators
Boolean, or logical, operators perform logical connective and negation operations. The operands of Boolean operators
are Boolean (True/False) values. The following table describes the Boolean operators:
66
Operator
Description
NOT
Reverse the value of an argument. For example, NOT True is False and the inverse.
or !
AND
or &&
OR
or ||
Return True if both arguments are True; return False otherwise. For example, True AND True is True, but True AND
False is False.
Return True if any of the arguments is True; return False otherwise. For example, True OR False is True, but False
OR False is False.
XOR
Exclusive or: Return True if one of the values is True and the other is False. Return False if both arguments are True
or both are False. For example, True XOR True is False, but True XOR False is True.
EQV
Equivalence: Return True if both operands are True or both are False. The EQV operator is the opposite of the XOR
operator. For example, True EQV True is True, but True EQV False is False.
IMP
Implication: The statement A IMP B is the equivalent of the logical statement If A Then B. A IMP B is False only if
A is True and B is False. It is True in all other cases.
Decision operators
The ColdFusion decision, or comparison, operators produce a Boolean True/False result. Many types of operation
have multiple equivalent operator forms. For example, IS and EQ perform the same operation. The following table
describes the decision operators:
Operator
Description
IS
Perform a case-insensitive comparison of two values. Return True if the values are identical.
EQUAL
EQ
IS NOT
NOT EQUAL
Opposite of IS. Perform a case-insensitive comparison of two values. Return True if the values
are not identical.
NEQ
CONTAINS
Return True if the value on the left contains the value on the right.
Opposite of CONTAINS. Return True if the value on the left does not contain the value on the
right.
GREATER THAN
Return True if the value on the left is greater than the value on the right.
GT
LESS THAN
LT
GREATER THAN OR EQUAL TO
Opposite of GREATER THAN. Return True if the value on the left is smaller than the value on the
right.
Return True if the value on the left is greater than or equal to the value on the right.
GTE
GE
LESS THAN OR EQUAL TO
Return True if the value on the left is less than or equal to the value on the right.
LTE
LE
67
Note: In CFScript expressions only, you can also use the following decision operators. You cannot use them in expressions
in tags. == (EQ), != (NEQ), > (GT), < (LT), >= (GTE), and <= (LTE).
Decision operator rules
The following rules apply to decision operators:
When ColdFusion evaluates an expression that contains a decision operator other than CONTAINS or DOES NOT
CONTAIN, it first determines if the data can be converted to numeric values. If they can be converted, it performs
a numeric comparison on the data. If they cannot be converted, it performs a string comparison. This can
sometimes result in unexpected results. For more information on this behavior, see Evaluation and type
conversion issues on page 53.
When ColdFusion evaluates an expression with CONTAINS or DOES NOT CONTAIN it does a string
comparison. The expression A CONTAINS B evaluates to True if B is a substring of A. Therefore an expression
such as the following evaluates as True:
123.45 CONTAINS 3.4
When a ColdFusion decision operator compares strings, it ignores the case. As a result, the following expression is
True:
"a" IS "A"
When a ColdFusion decision operator compares strings, it evaluates the strings from left to right, comparing the
characters in each position according to their sorting order. The first position where the characters differ
determines the relative values of the strings. As a result, the following expressions are True:
"ab" LT "aba"
"abde" LT "ac"
String operators
String operators manipulate strings of characters. The following table describes the operators:
Operator
Description
&
Concatenates strings.
&=
Compound concatenation. The variable on the right is used as both an element in the concatenation operation and
the result variable. Thus, the expression a &= b is equivalent to a = a & b.
An expression can have only one compound assignment operator.
If the Boolean expression evaluates to true, the operator result is expression1; otherwise, it is expression2
For example
<cfset c = (a GT b)? a : b >
68
The parentheses can contain any expression that evaluates to a Boolean value, and a and b can be any valid expression.
You can nest this operator inside other expressions.
6 - 3 * 2 is equal to 0
(6 - 3) * 2 is equal to 6
You can nest parenthesized expressions. When in doubt about the order in which operators in an expression are
evaluated, use parentheses to force the order of evaluation.
Rand()
Function syntax
The following table shows function syntax and usage guidelines:
Usage
Example
No arguments
Function()
Basic format
Function(Data)
Nested functions
Function1(Function2(Data))
Multiple arguments
String arguments
Function('This is a demo')
Function('This is a demo')
Function1(X*Y, Function2("Text"))
69
All functions return values. In the following example, the cfset tag sets a variable to the value returned by the Now
function:
<cfset myDate = DateFormat(Now(), "mmmm d, yyyy")>
You can use the values returned by functions directly to create more complex expressions, as in the following example:
Abs(Myvar)/Round(3.14159)
For more information on how to insert functions in expressions, see Using number signs on page 70.
Optional function arguments
Some functions take optional arguments after their required arguments. If omitted, all optional arguments default to
a predefined value. For example:
Replace("Eat and Eat", "Eat", "Drink", "All") returns "Drink and Drink"
The difference in the results is because the Replace function takes an optional fourth argument that specifies the scope
of replacement. The default value is One, which explains why only the first occurrence of Eat was replaced with
Drink in the first example. In the second example, a fourth argument causes the function to replace all occurrences
of Eat with Drink.
Expression evaluation and functions
It is important to remember that ColdFusion evaluates function attributes as expressions before it executes the
function. As a result, you can use any ColdFusion expression as a function attribute. For example, consider the
following lines:
<cfset firstVariable = "we all need">
<cfset myStringVar = UCase(firstVariable & " more sleep!")>
When ColdFusion server executes the second line, it does the following:
1 Identifies an expression with a string concatenation.
2 Evaluates the firstVariable variable as the string "we all need".
3 Concatenates "we all need" with the string "more sleep!" to get "we all need more sleep!".
4 Passes the string "we all need more sleep!" to the UCase function.
5 Executes the UCase function on the string argument "we all need more sleep!" to get "WE ALL NEED MORE
SLEEP!".
6 Assigns the string value "WE ALL NEED MORE SLEEP!" to the variable myStringVar.
You can use the var operator in multiple assignments, but the variables with this operator must precede all others. For
example:
70
In this example, the variable Form.MyFormVariable is replaced with the value assigned to it.
Follow these guidelines when using number signs:
Use number signs only where necessary, because unneeded number signs slow processing.
For a description of using number signs to create variable names, see Using number signs to construct a variable name
in assignments on page 74.
You can optionally omit quotation marks around variables used as attribute values as shown in the following example:
<cfcookie name = TestCookie value = #CookieValue#>
However, surrounding all attribute values in quotation marks is more consistent with HTML coding style.
If you use string expressions to construct an attribute value, as shown in the following example, the strings inside the
expression use single quotation marks (') to differentiate the quotation marks from the quotation marks that surround
the attribute value.
<cfcookie name="TestCookie2" value="The #CookieValue & 'ate the cookie!'#">
71
Note: You do not need to use number signs when you use the cfset tag to assign one variables value to another value. For
example, the following tag assigns the value of the oldVar variable to the new variable, newVar: <cfset newVar =
oldVar>.
cfoutput
cfquery
cfmail
For example:
<cfoutput>
Value is #Form.MyTextField#
</cfoutput>
<cfoutput>
The name is #FirstName# #LastName#.
</cfoutput>
<cfoutput>
The value of Cos(0) is #Cos(0)#
</cfoutput>
If you omit the number signs, the text, rather than the value, appears in the output generated by the cfoutput
statement.
Two expressions inside number signs can be adjacent to one another, as in the following example:
<cfoutput>
"Mo" and "nk" is #Left("Moon", 2)##Mid("Monkey", 3, 2)#
</cfoutput>
ColdFusion automatically replaces the text with the value of the variable or the value returned by the function. For
example, the following pairs of cfset statements produce the same result:
<cfset TheString = "Hello, #FirstName#!">
<cfset TheString = "Hello, " & FirstName & "!">
If number signs are omitted inside the string, the text, rather than the value, appears in the string. For example, the
following pairs of cfset statements produce the same result:
72
As with the cfoutput statement, two expressions can be adjacent to each other in strings, as in the following example:
<cfset TheString = "Monk is #Left("Moon", 2)##Mid("Monkey", 3, 2)#">
The double-quotation marks around "Moon" and "Monkey" do not need to be escaped (as in ""Moon"" and
""Monkey""). This is because the text between the number signs is treated as an expression; it is evaluated before its
value is inserted inside the string.
In this example, number signs are nested so that the values of the variables FirstName and LastName are inserted in
the string whose length the Len function calculates.
Nested number signs imply a complex expression that can typically be written more clearly and efficiently without the
nesting. For example, you can rewrite the preceding code example without the nested number signs, as follows:
<cfset Sentence2 = "The length of the full name is #Len(FirstName & " " & LastName)#">
The following achieves the same results and can further improve readability:
<cfset FullName = "#FirstName# #LastName#">
<cfset Sentence = "The length of the full name is #Len(FullName)#">
A common mistake is to place number signs around the arguments of functions, as in:
<cfset ResultText = "#Len(#TheText#)#">
<cfset ResultText = "#Min(#ThisVariable#, 5 + #ThatVariable#)#">
<cfset ResultText = "#Len(#Left("Some text", 4)#)#">
These statements result in errors. As a general rule, never place number signs around function arguments.
In contrast, the following example uses number signs unnecessarily and is less efficient than the previous statement:
<cfset #SomeVar# = #Var1# + #Max(Var2, 10 * Var3)# + #Var4#>
73
Using dynamic variables in this manner does not require dynamic evaluation.
Form applications where the number and names of fields on the form vary dynamically. In this case, the form posts
only the names and values of its fields to the action page. The action page does not know all the names of the fields,
although it does know how the field names (that is, the variable names) are constructed.
74
This does not mean that you must always avoid dynamic evaluation. However, given the substantial performance costs
of dynamic evaluation, first ensure that one of the following techniques cannot serve your purpose:
To construct a variable name this way, all the text on the left side of the equal sign must be in quotation marks.
This usage is less efficient than using arrays. The following example has the same purpose as the previous one, but
requires less processing:
<cfset MyArray=ArrayNew(1)>
<cfset prodNo = 12>
<cfset myArray[prodNo] = "Widget">
However, you can construct an array index value dynamically from variables without using quotation marks on the left
side of an assignment. For example, the preceding sample code works if you replace the final line with the following line:
<cfset myArray[#productClassNo# & #productItemNo#] = "Widget">
For an example of using this format to manage a shopping cart, see Example: a dynamic shopping cart on page 79.
75
Purpose
DE
Escapes any double-quotation marks in the argument and wraps the result in double-quotation marks. The
DE function is particularly useful with the IIF function, to prevent the function from evaluating a string to
be output.
For an example of using the DE function with the IIF function, see Using the IIF function on page 78.
Evaluate
Takes one or more string expressions and dynamically evaluates their contents as expressions from left to
right. (The results of an evaluation to the left can have meaning in an expression to the right.) Returns the
result of evaluating the rightmost argument.
For more information on this function see About the Evaluate function on page 75.
IIf
Evaluates a Boolean condition expression. Depending on whether this expression is True or False,
dynamically evaluates one of two string expressions and returns the result of the evaluation. The IIF
function is convenient for incorporating a cfif tag in line in HTML.
For an example of using this function, see Using the IIF function on page 78.
PrecisionEvaluate
Operates identically to the Evaluate function, except that it can calculate arbitrary precision decimal
arithmetic. If one or more operands in an arithmetic expression are decimal numbers, such as
12947834.986532, and are too long to be represented exactly by a ColdFusion numeric data type, the
function uses arbitrary-precision arithmetic to calculate the result, and return the result as an arbitrarily
long string of numbers. For more information about this function, see PrecisionEvaluate in the CFML
Reference.
SetVariable
Sets a variable identified by the first argument to the value specified by the second argument. This function
is no longer required in well-formed ColdFusion pages; see SetVariable function considerations on
page 78.
You might expect this line to display """1"" & ""2""". Instead, it displays 12, because ColdFusion processes the line as
follows:
1 Evaluates the expression "1" & "2" as the string 12.
2 Passes the string "12" (without the quotation marks) to the DE function.
3 Calls the DE function, which adds literal quotation marks around the 12.
Similarly, if you use the expression DE(1 + 2), ColdFusion evaluates 1 + 2 as the integer 3 and passes it to the function.
The function converts it to a string and surrounds the string in literal quotation marks: 3.
About the Evaluate function
The Evaluate function takes one or more string expressions, dynamically evaluates their contents as expressions from
left to right, and returns the result of evaluating the rightmost argument.
76
The following example shows the Evaluate function and how it works with ColdFusion variable processing:
<cfset myVar2="myVar">
<cfset myVar="27/9">
<cfoutput>
#myVar2#<br>
#myVar#<br>
#Evaluate("myVar2")#<br>
#Evaluate("myVar")#<br>
#Evaluate(myVar2)#<br>
#Evaluate(myVar)#<br>
</cfoutput>
Description
<cfset myVar2="myVar">
<cfset myVar="27/9">
myVar
27/9
<cfoutput>
Displays the values assigned to the variables, myVar and 27/9, respectively.
#myVar2#<br/>
#myVar#<br/>
#Evaluate("myVar2")#<br>
Passes the string "myvar2" (without the quotation marks) to the Evaluate function, which
does the following:
1
2 Returns the value of the myVar2 variable, the string "myvar" (without the quotation
marks).
#Evaluate("myVar")#<br>
Passes the string "myvar" (without the quotation marks) to the Evaluate function, which
does the following:
1
Returns the value of the myVar variable, the string "27/9" (without the quotation marks).
#Evaluate(myVar2)#<br>
Evaluates the variable myVar2 as the string "myVar" and passes the string (without the
quotation marks) to the Evaluate function. The rest of the processing is the same as in the
previous line.
#Evaluate(myVar)#<br/>
Evaluates the variable myVar as the string "27/9" (without the quotation marks), and passes
it to the Evaluate function, which does the following:
</cfoutput>
As you can see, using dynamic expressions can result in substantial expression evaluation overhead, and the code can
be confusing. Therefore, you should avoid using dynamic expressions wherever a simpler technique, such as using
indexed arrays or structures can serve your purposes.
Avoiding the Evaluate function
Using the Evaluate function increases processing overhead, and in most cases it is not necessary. These examples
show some cases where you can consider using the Evaluate function:
77
Example 1
You might be inclined to use the Evaluate function in code such as the following:
<cfoutput>1 + 1 is #Evaluate(1 + 1)#</cfoutput>
Example 2
This example shows how you can use an associative array reference in place of an Evaluate function. This technique
is powerful because:
This code comes from an example where a form has entries for an indeterminate number of items in a shopping cart.
A product name field exists for each item in the shopping cart. The field name is of the form product_1, product_2,
and so on, where the number corresponds to the product entry in the shopping cart. In this example, ColdFusion does
the following:
1 Replaces the variable i with its value, for example 1.
2 concatenates the variable value with "Form.product_", and passes the result (for Form.product_1) to the Evaluate
run its parser, this step requires substantial processing, even for a simple variable.
4 Evaluates the representation of the variable, for example as "Air popper".
5 Returns the value of the variable.
The following example has the same result as the preceding example and is more efficient:
<cfoutput>
ProductName: #Form["product_" & i]#
</cfoutput>
of the variable i.
2 Determines the value of the variable i; 1.
3 Concatenates the string and the variable value to get product_1.
4 Uses the result as the key value in the Form structure to get Form[product_1]. This associative array reference
accesses the same value as the object.attribute format reference Form.product_1; in this case, Air popper.
This code format does not use any dynamic evaluation, but it achieves the same effect, of dynamically creating a
structure reference by using a string and a variable.
78
In the second line, enclosing the myVar#i# variable name in quotation marks tells ColdFusion to evaluate the name
and process any text in number signs as a variable or function. ColdFusion replaces the #i# with the value of the
variable i, so that if the value of i is 12, this code is equivalent to the line
<cfset myVar12 = myVal>
For more information on this usage, see Using number signs to construct a variable name in assignments on page 74.
The function returns the value of the result variable. It is comparable to the use of the JavaScript and Java ? : operator,
and can result in more compact code. As a result, the IIF function can be convenient even if you are not using dynamic
expressions.
The IIF function requires the DE function to prevent ColdFusion from evaluating literal strings, as the following
example shows:
<cfoutput>
#IIf(IsDefined("LocalVar"), "LocalVar", DE("The variable is not defined."))#
</cfoutput>
If you do not enclose the string "The variable is not defined." in a DE function, the IIF function tries to evaluate the
contents of the string as an expression and generates an error (in this case, an invalid parser construct error).
The IIF function is useful for incorporating ColdFusion logic in line in HTML code, but it entails a processing time
penalty in cases where you do not otherwise need dynamic expression evaluation.
The following example shows using IIF to alternate table row background color between white and gray. It also shows
the use of the DE function to prevent ColdFusion from evaluating the color strings.
<cfoutput>
<table border="1" cellpadding="3">
<cfloop index="i" from="1" to="10">
<tr bgcolor="#IIF( i mod 2 eq 0, DE("white"), DE("gray") )#">
<td>
hello #i#
</td>
</tr>
</cfloop>
</table>
</cfoutput>
This code is more compact than the following example, which does not use IIF or DE:
79
<cfoutput>
<table border="1" cellpadding="3">
<cfloop index="i" from="1" to="10">
<cfif i mod 2 EQ 0>
<cfset Color = "white">
<cfelse>
<cfset Color = "gray">
</cfif>
<tr bgcolor="#color#">
<td>
hello #i#
</td>
</tr>
</cfloop>
</table>
</cfoutput>
80
81
Code
Description
<cfscript>
CartItems=4;
Cart = ArrayNew(1);
for ( i=1; i LE cartItems; i=i+1)
{
Cart[i]=StructNew();
Cart[i].ID=i;
Cart[i].Name="Product " & i;
Cart[i].SKU=i*100+(2*i*10)+(3*i);
Cart[i].Qty=3*i-2;
}
</cfscript>
<cfform name="ShoppingCart"
action="ShoppingCartAction.cfm" method="post">
<table>
<tr>
<td>Order?</td>
<td>Product</td>
<td>Code</td>
<td>Quantity</td>
</tr>
Start the form and its embedded table. When the user clicks the
submit button, post the form data to the ShoppingCartAction.cfm
page.
Loop through the shopping cart entries to generate the cart form
dynamically. For each loop, generate variables used for the form field
name attributes by appending the cart item ID (Cart[i].ID) to a field
type identifier, such as "sku_".
The table formats the form neatly. The first table row contains the
column headers. Each following row has the data for one cart item.
Use a single name, "itemID", for all check boxes. This way, the itemID
value posted to the action page is a list of all the check box field
values. The check box field value for each item is the cart item ID.
Each column in a row contains a field for a cart item structure entry.
The passthrough attribute sets the product name and SKU fields to
read only; note the use of single-quotation marks. (For more
information on the cfinput tag passthrough attribute, see the CFML
Reference.) The check boxes are selected by default.
82
<html>
<head>
<title>Your Order</title>
</head>
<body>
<cfif isDefined("Form.submit")>
<cfparam name="Form.itemID" default="">
<cfoutput>
You have ordered the following items:<br>
<br>
<cfloop index="i" list="#Form.itemID#">
ProductName: #Form["product_" & i]#<br>
Product Code: #Form["sku_" & i]#<br>
Quantity: #Form["qty_" & i]#<br>
<br>
</cfloop>
</cfoutput>
</cfif>
</body>
</html>
Description
<cfif isDefined("Form.submit")>
Run the CFML on this page only if it is called by submitting a form. This is not needed
if the form and action pages are separate, but is required if the form and action page
were one ColdFusion page.
Set the default Form.itemID to the empty string. This prevents ColdFusion from
displaying an error if the user clears all check boxes before submitting the form (so
no product IDs are submitted).
<cfoutput>
You have ordered the following items:<br>
<br>
<cfloop index="i" list="#Form.itemID#">
ProductName: #Form["product_" & i]#<br>
Product Code: #Form["sku_" & i]#<br>
Quantity: #Form["qty_" & i]#<br>
<br>
</cfloop>
</cfoutput>
</cfif>
Display the name, SKU number, and quantity for each ordered item.
The form page posts Form.itemID as a list containing the value attributes of all the
check boxes. These attributes contain the shopping cart item IDs for the selected cart
items. Use the list values to index a loop that outputs each ordered item.
Use associative array notation to access the Form scope as a structure and use
expressions in the array indexes to construct the form variable names. The
expressions consist of a string containing the field names field type prefix (for
example, "sku_"), concatenated with the variable i, which contains the shopping cart
ItemID number (which is also the loop index variable).
83
About arrays
Traditionally, an array is a tabular structure used to hold data, much like a spreadsheet table with clearly defined limits
and dimensions.
In ColdFusion, you typically use arrays to temporarily store data. For example, if your site lets users order goods
online, you can store their shopping cart contents in an array. Using an array lets you make changes easily without
committing the information, which the user can change before completing the transaction, to a database.
my2Darray[1][1], my3Darray[1][1][1].
Array element: Data stored at an array index.
The simplest array is a one-dimensional array, like a row in a table. A one-dimensional array has a name (the variable
name) and a numeric index. The index number references a single entry, or cell, in the array.
Thus, the following statement sets the value of the fifth entry in the one-dimensional array MyArray to Robert:
<cfset MyArray[5] = "Robert">
A basic two-dimensional (2D) array is like a simple table. A three-dimensional (3D) array is like a cube of data, and so
on. ColdFusion lets you directly create arrays with up to three dimensions. You can use multiple statements to create
arrays with more than three dimensions.
The syntax my2darray[1][3]="Paul" is the same as saying My2dArray is a two-dimensional array and the value of
the array element index [1][3] is Paul.
84
a[1]
a[2]
a[2][1]
a[3]
a[3][1] a[3][2]
a[4]
a[4][1]
a[2][5]
a[4][3]
A ColdFusion 3D array is essentially three nested sets of 1D arrays. The differences between traditional and
ColdFusion 3D arrays are similar, but much harder to show on a page.
Dynamic arrays expand to accept data that you add to them and contract as you remove data from them.
Note: The IsDefined function does not test the existence of array elements. Instead, place any code that could try to
access an undefined array element in a try block and use a catch block to handle exceptions that arise if elements do not
exist.
Creating arrays
In ColdFusion, you can create arrays explicitly, by using a function to declare the array and then assigning it data, or
implicitly by using an assignment statement. You can create simple or complex, multidimensional arrays.
85
This line creates a two-dimensional array named myNewArray. You use this method to create an array with up to three
dimensions.
After you create an array, you add array elements, which you can then reference by using the element indexes.
For example, suppose you create a one-dimensional array called firstname:
<cfset firstname=ArrayNew(1)>
The array firstname holds no data and is of an unspecified length. Next you add data to the array:
<cfset firstname[1]="Coleman">
<cfset firstname[2]="Charlie">
<cfset firstname[3]="Dexter">
This single statement is equivalent to the four statements used to create the firstname array in Creating arrays using
functions on page 85.
When you create an array implicitly, the right side of the assignment statement has brackets ([]) surrounding the array
contents and commas separating the individual array elements. The elements can be literal values, such as the strings
in the example, variables, or expressions. If you specify variables, do not place the variable names in quotation marks.
You can create an empty array implicitly, as in the following example:
<cfset myArray = []>
You can also create an array implicitly by assigning a single entry, as the following example shows:
<cfset chPar[1] = "Charlie">
<cfset chPar[2] = "Parker">
ColdFusion does not allow nested implicit creation of arrays, structures, or arrays and structures. Therefore, you
cannot create a multidimensional array in a single implicit statement. For example, neither of the following statements
is valid:
<cfset myArray = [[],[]]>
<cfset jazzmen = [["Coleman","Charlie"],["Hawkins", "Parker"]]
To create a two-dimensional array, for example, use a format such as the following:
<cfset ch = ["Coleman", "Hawkins"]>
<cfset cp = ["Charlie", "Parker"]>
<cfset dg = ["Dexter", "Gordon"]>
<cfset players = [ch, cp, dg]>
You cannot use a dynamic variable when you create an array implicitly. For example, the following expression
generates an error:
86
<cfset i="CP">
<cfset "#i#"=["Charlie","Parker"]>
biggerarray[1][1][1]=myarray>
biggerarray[1][1][1][10]=3>
biggerarray[2][1][1]=myotherarray>
biggerarray[2][1][1][4][2]="five deep">
<cfset
<cfset
<cfset
<cfset
biggestarray=ArrayNew(3)>
biggestarray[3][1][1]=biggerarray>
biggestarray[3][1][1][2][3][1]="This is complex">
myarray[3]="Can you see me">
<cfdump var=#biggestarray#><br>
<cfdump var=#myarray#>
Note: The cfdump tag displays the entire contents of an array. It is an excellent tool for debugging arrays and arrayhandling code.
Reviewing the code
The following table describes the code:
Code
Description
<cfset myarray=ArrayNew(1)>
<cfset myotherarray=ArrayNew(2)>
<cfset biggerarray=ArrayNew(3)>
<cfset biggerarray[1][1][1]=myarray>
<cfset biggerarray[1][1][1][10]=3>
<cfset biggerarray[2][1][1]=myotherarray>
<cfset biggerarray[2][1][1][4][2]="five deep">
87
Code
Description
<cfset biggestarray=ArrayNew(3)>
Create a second 3D array. Make the [3][1][1] element of this
<cfset biggestarray[3][1][1]=biggerarray>
array a copy of the biggerarray array, and assign element
<cfset biggestarray[3][1][1][2][3][1]="This is complex"> [3][1][1][2][3][1].
<cfdump var=#biggestarray#><br>
<cfdump var=#myarray#>
If an element does not exist at the specified index, ColdFusion creates it. If an element exists at the specified index,
ColdFusion replaces it with the new value. To prevent existing data from being overwritten, use the ArrayInsertAt
function, as described in the next section.
If elements with lower-number indexes do not exist, they remain undefined. Assign values to undefined array elements
before you can use them. For example, the following code creates an array and an element at index 4. It outputs the
contents of element 4, but generates an error when it tries to output the (nonexistent) element 3.
<cfset myarray=ArrayNew(1)>
<cfset myarray[4]=4>
<cfoutput>
myarray4: #myarray[4]#<br>
myarray3: #myarray[3]#<br>
</cfoutput>
88
Description
ArrayAppend
ArrayPrepend
ArrayInsertAt
Because ColdFusion arrays are dynamic, if you add or delete an element from the array, any higher-numbered index
values all change. For example, the following code creates a two element array and displays the array contents. It then
uses ArrayPrepend to insert a new element at the beginning of the array and displays the result. The data that was
originally in indexes 1 and 2 is now in indexes 2 and 3.
<!--- Create an array with three elements. --->
<cfset myarray=ArrayNew(1)>
<cfset myarray[1]="Original First Element">
<cfset myarray[2]="Original Second Element">
<!--- Use cfdump to display the array structure --->
<cfdump var=#myarray#>
<br>
<!--- Add a new element at the beginning of the array. --->
<cfscript>
ArrayPrepend(myarray, "New First Element");
</cfscript>
<!--- Use cfdump to display the new array structure. --->
<cfdump var=#myarray#>
For more information about these array functions, see the CFML Reference.
The ArrayDeleteAt function removed the original second element and resized the array so that it has two entries,
with the second element now being the original third element.
89
Copying arrays
You can copy arrays of simple variables (numbers, strings, Boolean values, and date-time values) by assigning the
original array to a new variable name. You do not have to use ArrayNew to create the array first. When you assign the
existing array to a new variable, ColdFusion creates an array and copies the contents of the old array to the new array.
The following example creates and populates a two-element array. It then copies the original array, changes one
element of the copied array and dumps both arrays. As you can see, the original array is unchanged and the copy has
a new second element.
<cfset myArray=ArrayNew(1)>
<cfset myArray[1]="First Array Element">
<cfset myArray[2]="Second Array Element">
<cfset newArray=myArray>
<cfset newArray[2]="New Array Element 2">
<cfdump var=#myArray#><br>
<cfdump var=#newArray#>
If your array contains complex variables (structures, query objects, or external objects such as COM objects) assigning
the original array to a new variable does not make a complete copy of the original array. The array structure is copied;
however, the new array does not get its own copy of the complex data, only references to it. To demonstrate this
behavior, run the following code:
Create an array that contains a structure.<br>
<cfset myStruct=StructNew()>
<cfset myStruct.key1="Structure key 1">
<cfset myStruct.key2="Structure key 2">
<cfset myArray=ArrayNew(1)>
<cfset myArray[1]=myStruct>
<cfset myArray[2]="Second array element">
<cfdump var=#myArray#><br>
<br>
Copy the array and dump it.<br>
<cfset myNewArray=myArray>
<cfdump var=#myNewArray#><br>
<br>
Change the values in the new array.<br>
<cfset myNewArray[1].key1="New first array element">
<cfset myNewArray[2]="New second array element">
<br>
Contents of the original array after the changes:<br>
<cfdump var=#myArray#><br>
Contents of the new array after the changes:<br>
<cfdump var=#myNewArray#>
The change to the new array also changes the contents of the structure in the original array.
To make a complete copy of an array that contains complex variables, use the Duplicate function.
90
The following example initializes the array myarray, indexes 1 - 100, with an empty string:
ArraySet (myarray, 1, 100, "")
91
<cfset my2darray=arraynew(2)>
<cfloop index="loopcount" from=1 to=12>
<cfloop index="loopcount2" from=1 to=2>
<cfset my2darray[loopcount][loopcount2]=(loopcount * loopcount2)>
</cfloop>
</cfloop>
<p>The values in my2darray are currently:</p>
<cfloop index="OuterCounter" from="1" to="#ArrayLen(my2darray)#">
<cfloop index="InnerCounter" from="1"to="#ArrayLen(my2darray[OuterCounter])#">
<cfoutput>
<b>[#OuterCounter#][#InnerCounter#]</b>:
#my2darray[OuterCounter][InnerCounter]#<br>
</cfoutput>
</cfloop>
</cfloop>
You cannot add query data to an array all at once. A looping structure is often required to populate an array from
a query.
You can reference query column data using array-like syntax. For example, myquery.col_name[1] references data
in the first row in the col_name column of the myquery query.
Inside a cfloopquery= loop, you do not have to specify the query name to reference the query variables.
You can use a cfset tag with the following syntax to define values for array indexes:
<cfset arrayName[index]=queryColumn[row]>
In the following example, a cfloop tag places four columns of data from a sample data source into an array, myarray.
92
This example uses the query object built-in variable CurrentRow to index the first dimension of the array.
Array functions
The following functions are available for creating, editing, and handling arrays:
Function
Description
ArrayAppend
ArrayAvg
ArrayClear
ArrayDeleteAt
Deletes an element from a specified array at the specified index and resizes the array.
ArrayInsertAt
Inserts an element (with data) in a specified array at the specified index and resizes the array.
ArrayIsDefined
ArrayIsEmpty
ArrayLen
ArrayMax
ArrayMin
ArrayNew
ArrayPrepend
ArrayResize
93
Function
Description
ArraySet
ArraySort
ArraySum
ArraySwap
ArrayToList
Converts the specified 1D array to a list, delimited with the character you specify.
IsArray
ListToArray
Converts the specified list, delimited with the character you specify, to an array.
For more information about each of these functions, see the CFML Reference.
If a function returns an array, you can now reference a specific element array directly in the function call statement.
For example, the following line references the fifth element of the array returned by the myFunc() function:
myFunc()[5]
About structures
ColdFusion structures consist of key-value pairs. Structures let you build a collection of related variables that are
grouped under a single name. You can define ColdFusion structures dynamically.
You can use structures to reference related values as a unit, rather than individually. To maintain employee lists, for
example, you can create a structure that holds personnel information such as name, address, phone number, ID
numbers, and so on. Then you can reference this collection of information as a structure called employee rather than
as a collection of individual variables.
A structure key must be a string. The values associated with the key can be any valid ColdFusion value or object. It can
be a string or integer, or a complex object such as an array or another structure. Because structures can contain any
types of data, they provide a powerful and flexible mechanism for representing complex data.
Structure notation
ColdFusion supports three types of notation for referencing structure contents. The notation that you use depends on
your requirements.
94
Notation
Description
Object.property
You can reference a property, prop, of an object, obj, as obj.prop. This notation, also called dot notation, is
useful for simple assignments, as in this example:
depts.John="Sales"
Use this notation only when you know the property names (keys) in advance and they are strings, with no
special characters, numbers, or spaces. You cannot use the dot notation when the property, or key, is
dynamic.
Associative arrays
If you do not know the key name in advance, or it contains spaces, numbers, or special characters, you can
use associative array notation. This notation uses structures as arrays with string indexes; for example:
depts["John"]="Sales"
depts[employeeName] = "Sales"
You can use a variable (such as employeeName) as an associative array index. Therefore, enclose any literal
key names in quotation marks.
For information on using associative array references containing variables, see Dynamically constructing
structure references on page 74.
Structure
Use structure notation only when you create structures and set their initial values, not when you are
accessing or updating structure data, and only on the right side of an assignment expression. This notation
has the following format:
{keyName=value[,keyName=value]...}
where the square braces ([]) and ellipses (...) indicate optional contents that can be repeated.
The following example creates a structure that uses structure notation:
<cfset name={firstName = "John", lastName = "Smythe"}>
The following example shows various ways you can reference the contents of a complex structure:
95
<cfset myArray=ArrayNew(1)>
<cfset myArray[1]="2">
<cfset myArray[2]="3">
<cfset myStruct2=StructNew()>
<cfset myStruct2.struct2key1="4">
<cfset myStruct2.struct2key2="5">
<cfset myStruct=StructNew()>
<cfset myStruct.key1="1">
<cfset myStruct.key2=myArray>
<cfset myStruct.key3=myStruct2>
<cfdump var=#myStruct#><br>
<cfset
<cfset
<cfset
<cfset
key1Var="key1">
key2Var="key2">
key3Var="key3">
var2="2">
<cfoutput>
Value of the first key<br>
#mystruct.key1#<br>
#mystruct["key1"]#<br>
#mystruct[key1Var]#<br>
<br>
Value of the second entry in the key2 array<br>
#myStruct.key2[2]#<br>
#myStruct["key2"][2]#<br>
#myStruct[key2Var][2]#<br>
#myStruct[key2Var][var2]#<br>
<br>
Value of the struct2key2 entry in the key3 structure<br>
#myStruct.key3.struct2key2#<br>
#myStruct["key3"]["struct2key2"]#<br>
#myStruct[key3Var]["struct2key2"]#<br>
#myStruct.key3["struct2key2"]#<br>
#myStruct["key3"].struct2key2#<br>
<br>
</cfoutput>
Description
myArray=ArrayNew(1)>
myArray[1]="2">
myArray[2]="3">
myStruct2=StructNew()>
myStruct2.struct2key1="4">
myStruct2.struct2key2="5">
myStruct=StructNew()>
myStruct.key1="1">
myStruct.key2=myArray>
myStruct.key3=myStruct2>
<cfdump var=#myStruct#><br>
<cfset key1Var="key1">
<cfset key2Var="key2">
<cfset key3Var="key3">
Create variables containing the names of the myStruct keys and the
number 2.
96
Code
Description
<cfoutput>
Value of the first key<br>
#mystruct.key1#<br>
#mystruct["key1"]#<br>
#mystruct[key1Var]#<br>
<br>
Output the value of the key1 (string) entry using the following
notation:
<br>
Value of the second entry in the key2 array<br>
#myStruct.key2[2]#<br>
#myStruct["key2"][2]#<br>
#myStruct[key2Var][2]#<br>
#myStruct[key2Var][var2]#<br>
<br>
object.property notation
Output the value of the second entry in the key2 array using the
following notation:
object.property notation
associative array notation with variables for both the array and the
array index
object.property notation
Creating structures
In ColdFusion, you can create structures explicitly by using a function, and then populate the structure using
assignment statements or functions, or you can create the structure implicitly by using an assignment statement.
Creating structures using functions
You can create structures by assigning a variable name to the structure with the StructNew function as follows:
<cfset structName = StructNew()>
For example, to create a structure named departments, use the following syntax:
<cfset departments = StructNew()>
This statement creates an empty structure to which you can add data.
Creating structures implicitly
You can create an empty structure implicitly, as in the following example:
<cfset myStruct = {}>
97
You can also create a structure by assigning data to a variable. For example, each of the following lines creates a
structure named myStruct with one element, name, that has the value Adobe Systems Incorporated.
<cfset coInfo.name = "Adobe Systems Incorporated">
<cfset coInfo["name"] = "Adobe Systems Incorporated">
<cfset coInfo = {name = "Adobe Systems Incorporated"}>
When you use structure notation to create a structure, as shown in the third example, you can populate multiple
structure fields. The following example shows this use:
<cfset coInfo={name="Adobe Systems Incorporated", industry="software"}
ColdFusion does not allow nested implicit creation of structures, arrays, or structures and arrays. The following line,
for example, generates an error:
<cfset myStruct = {structKey1 = {innerStructKey1 = "innerStructValue1"}}>
Similarly, you cannot use object.property notation on the left side of assignments inside structure notation. The
following statement, for example, causes an error:
<cfset myStruct={structKey1.innerStructKey1 = "innerStructValue1"}>
Instead of using these formats, use multiple statements, such as the following:
<cfset innerStruct1 = {innerStructKey1 = "innerStructValue1"}
<cfset myStruct1={structKey1 = innerStruct1}>
You cannot use a dynamic variable when you create a structure implicitly. For example, the following expression
generates an error:
<cfset i="coInfo">
<cfset "#i#"={name = ""Adobe Systems Incorporated"}>
You can use array notation inside the structure notation, as shown in the following example:
<cfset student = {firstName="Jane", lastName="Janes", grades=[91, 78, 87]}>
The following code uses cfset and object.property notation to create a structure element called departments.John,
and changes Johns department from Sales to Marketing. It then uses associative array notation to change his
department to Facilities. Each time the department changes, it displays the results:
98
<cfset departments=structnew()>
<cfset departments.John = "Sales">
<cfoutput>
Before the first change, John was in the #departments.John# Department<br>
</cfoutput>
<cfset Departments.John = "Marketing">
<cfoutput>
After the first change, John is in the #departments.John# Department<br>
</cfoutput>
<cfset Departments["John"] = "Facilities">
<cfoutput>
After the second change, John is in the #departments.John# Department<br>
</cfoutput>
This function returns True if variable is a ColdFusion structure. (It also returns True if variable is a Java object that
implements the java.util.Map interface.)
Structures are not indexed numerically, so to find out how many name-value pairs exist in a structure, use the
StructCount function, as in the following example:
StructCount(employee)
To discover whether a specific Structure contains data, use the StructIsEmpty function, as follows:
StructIsEmpty(structure_name)
This function returns True if the structure is empty, and False if it contains data.
Finding a specific key and its value
To determine whether a specific key exists in a structure, use the StructKeyExists function, as follows:
StructKeyExists(structure_name, "key_name")
Do not place the name of the structure in quotation marks, but you do place the key name in quotation marks. For
example, the following code displays the value of the MyStruct.MyKey only if it exists:
<cfif StructKeyExists(myStruct, "myKey")>
<cfoutput> #mystruct.myKey#</cfoutput><br>
</cfif>
You can use the StructKeyExists function to dynamically test for keys by using a variable to represent the key name.
In this case, you do not place the variable in quotation marks. For example, the following code loops through the
records of the GetEmployees query and tests the myStruct structure for a key that matches theLastName field of the
query. If ColdFusion finds a matching key, it displays the Last Name from the query and the corresponding entry in
the structure.
99
<cfloop query="GetEmployees">
<cfif StructKeyExists(myStruct, LastName)>
<cfoutput>#LastName#: #mystruct[LastName]#</cfoutput><br>
</cfif>
</cfloop>
If the name of the key is known in advance, you can also use the ColdFusion IsDefined function, as follows:
IsDefined("structure_name.key")>
However, if the key is dynamic, or contains special characters, use the StructKeyExists function.
Note: Using StructKeyExists to test for the existence of a structure entry is more efficient than using IsDefined.
ColdFusion scopes are available as structures and you can improve efficiency by using StructKeyExists to test for the
existence of variables.
Getting a list of keys in a structure
To get a list of the keys in a CFML structure, you use the StructKeyList function, as follows:
<cfset temp=StructKeyList(structure_name, [delimiter])>
You can specify any character as the delimiter; the default is a comma.
Use the StructKeyArray function to returns an array of keys in a structure, as follows:
<cfset temp=StructKeyArray(structure_name)>
Note: The StructKeyList and StructKeyArray functions do not return keys in any particular order. Use the
ListSort or ArraySort functions to sort the results.
Copying structures
ColdFusion provides several ways to copy structures and create structure references. The following table lists these
methods and describes their uses:
Technique
Use
Duplicate function
Makes a complete copy of the structure. All data is copied from the original structure to the new structure,
including the contents of structures, queries, and other objects. As a result changes to one copy of the structure
have no effect on the other structure.
This function is useful when you want to move a structure completely into a new scope. In particular, if a structure
is created in a scope that requires locking (for example, Application), you can duplicate it into a scope that does
not require locking (for example, Request), and then delete it in the scope that requires locking.
StructCopy function
Makes a shallow copy of a structure. It creates a structure and copies all simple variable and array values at the top
level of the original structure to the new structure. However, it does not make copies of any structures, queries, or
other objects that the original structure contains, or of any data inside these objects. Instead, it creates a reference
in the new structure to the objects in the original structure. As a result, any change to these objects in one
structure also changes the corresponding objects in the copied structure.
The Duplicate function replaces this function for most, if not all, purposes.
Variable assignment
Creates an additional reference, or alias, to the structure. Any change to the data using one variable name changes
the structure that you access using the other variable name.
This technique is useful when you want to add a local variable to another scope or otherwise change the scope of
a variable without deleting the variable from the original scope.
The following example shows the different effects of copying, duplicating, and assigning structure variables:
100
Create a structure<br>
<cfset myNewStructure=StructNew()>
<cfset myNewStructure.key1="1">
<cfset myNewStructure.key2="2">
<cfset myArray=ArrayNew(1)>
<cfset myArray[1]="3">
<cfset myArray[2]="4">
<cfset myNewStructure.key3=myArray>
<cfset myNewStructure2=StructNew()>
<cfset myNewStructure2.Struct2key1="5">
<cfset myNewStructure2.Struct2key2="6">
<cfset myNewStructure.key4=myNewStructure2>
<cfdump var=#myNewStructure#><br>
<br>
A StructCopy copied structure<br>
<cfset CopiedStruct=StructCopy(myNewStructure)>
<cfdump var=#CopiedStruct#><br>
<br>
A Duplicated structure<br>
<cfset dupStruct=Duplicate(myNewStructure)>
<cfdump var=#dupStruct#><br>
<br>
A new reference to a structure<br>
<cfset structRef=myNewStructure>
<cfdump var=#structRef#><br>
<br>
Change a string, array element, and structure value in the StructCopy copy.<br>
<br>
<cfset CopiedStruct.key1="1A">
<cfset CopiedStruct.key3[2]="4A">
<cfset CopiedStruct.key4.Struct2key2="6A">
Original structure<br>
<cfdump var=#myNewStructure#><br>
Copied structure<br>
<cfdump var=#CopiedStruct#><br>
Duplicated structure<br>
<cfdump var=#DupStruct#><br>
Structure reference
<cfdump var=#structRef#><br>
<br>
Change a string, array element, and structure value in the Duplicate.<br>
<br>
<cfset DupStruct.key1="1B">
<cfset DupStruct.key3[2]="4B">
<cfset DupStruct.key4.Struct2key2="6B">
Original structure<br>
<cfdump var=#myNewStructure#><br>
Copied structure<br>
<cfdump var=#CopiedStruct#><br>
Duplicated structure<br>
<cfdump var=#DupStruct#><br>
Structure reference
<cfdump var=#structRef#><br>
<br>
Change a string, array element, and structure value in the reference.<br>
<br>
101
<cfset structRef.key1="1C">
<cfset structRef.key3[2]="4C">
<cfset structRef.key4.Struct2key2="6C">
Original structure<br>
<cfdump var=#myNewStructure#><br>
Copied structure<br>
<cfdump var=#CopiedStruct#><br>
Duplicated structure<br>
<cfdump var=#DupStruct#><br>
Structure reference
<cfdump var=#structRef#><br>
<br>
Clear the original structure<br>
<cfset foo=structclear(myNewStructure)>
Original structure:<br>
<cfdump var=#myNewStructure#><br>
Copied structure<br>
<cfdump var=#CopiedStruct#><br>
Duplicated structure<br>
<cfdump var=#DupStruct#><br>
Structure reference:<br>
<cfdump var=#structRef#><br>
The indicateNotExisting argument tells the function what to do if the specified key does not exist. By default, the
function always returns True. However, if you specify True for the indicateNotExisting argument, the function returns
True if the key exists and False if it does not.
You can also use the StructClear function to delete all the data in a structure but keep the structure instance itself,
as follows:
StructClear(structure_name)
If you use StructClear to delete a structure that you have copied using the StructCopy function, the specified
structure is deleted, but the copy is unaffected.
If you use StructClear to delete a structure that has multiple references, the function deletes the contents of the
structure and all references point to the empty structure, as the following example shows:
<cfset myStruct.Key1="Adobe">
Structure before StructClear<br>
<cfdump var="#myStruct#">
<cfset myCopy=myStruct>
<cfset StructClear(myCopy)>
After Clear:<br>
myStruct: <cfdump var="#myStruct#"><br>
myCopy: <cfdump var="#myCopy#">
102
Structure examples
Structures are useful for grouping a set of variables under a single name. The following example uses structures to
collect information from a form, and to submit that information to a custom tag, named cf_addemployee. For
information on creating and using custom tags, see Creating and Using Custom CFML Tags on page 208.
103
<cfelse>
<cfoutput>
<cfscript>
employee=StructNew();
employee.firstname = Form.firstname;
employee.lastname = Form.lastname;
employee.email = Form.email;
employee.phone = Form.phone;
employee.department = Form.department;
</cfscript>
<!--- Display results of creating the structure. --->
First name is #StructFind(employee, "firstname")#<br>
Last name is #StructFind(employee, "lastname")#<br>
EMail is #StructFind(employee, "email")#<br>
Phone is #StructFind(employee, "phone")#<br>
Department is #StructFind(employee, "department")#<br>
</cfoutput>
<!--- Call the custom tag that adds employees. --->
<cf_addemployee empinfo="#employee#">
</cfif>
<!--- The form for adding the new employee information --->
<hr>
<form action="newemployee.cfm" method="Post">
First Name:
<input name="firstname" type="text" hspace="30" maxlength="30"><br>
Last Name:
<input name="lastname" type="text" hspace="30" maxlength="30"><br>
EMail:
<input name="email" type="text" hspace="30" maxlength="30"><br>
Phone:
<input name="phone" type="text" hspace="20" maxlength="20"><br>
Department:
<input name="department" type="text" hspace="30" maxlength="30"><br>
<input type="Submit" value="OK">
</form>
<br>
</body>
</html>
104
Code
<cfparam
<cfparam
<cfparam
<cfparam
<cfparam
Description
name="Form.firstname" default="">
name="Form.lastname" default="">
name="Form.email" default="">
name="Form.phone" default="">
name="Form.department" default="">
Set default values of all form fields so that they exist the first
time this page is displayed and can be tested.
Test the value of the firstname field. This field is required. The
test is False the first time the page displays.
If no data exists in the Form.firstname variable, display a
message requesting the user to fill the form.
<cfelse>
<cfoutput>
<cfscript>
employee=StructNew();
employee.firstname = Form.firstname;
employee.lastname = Form.lastname;
employee.email = Form.email;
employee.phone = Form.phone;
employee.department = Form.department;
</cfscript>
The data form. When the user clicks OK, the form posts the data
to this ColdFusion page.
105
<cfif StructIsEmpty(attributes.empinfo)>
<cfoutput>
Error. No employee data was passed.<br>
</cfoutput>
<cfexit method="ExitTag">
<cfelse>
<!--- Add the employee --->
<cfquery name="AddEmployee" datasource="cfdocexamples">
INSERT INTO Employees
(FirstName, LastName, Email, Phone, Department)
VALUES (
'#attributes.empinfo.firstname#' ,
'#attributes.empinfo.lastname#' ,
'#attributes.empinfo.email#' ,
'#attributes.empinfo.phone#' ,
'#attributes.empinfo.department#' )
</cfquery>
</cfif>
<cfoutput>
<hr>Employee Add Complete
</cfoutput>
Description
<cfif StructIsEmpty(attributes.empinfo)>
<cfoutput>
Error. No employee data was passed.<br>
</cfoutput>
<cfexit method="ExitTag">
<cfelse>
<!--- Add the employee --->
<cfquery name="AddEmployee" datasource="cfdocexamples">
INSERT INTO Employees
(FirstName, LastName, Email, Phone, Department)
VALUES (
'#attributes.empinfo.firstname#' ,
'#attributes.empinfo.lastname#' ,
'#attributes.empinfo.email#' ,
'#attributes.empinfo.phone#' ,
'#attributes.empinfo.department#' )
</cfquery>
</cfif>
<cfoutput>
<hr>Employee Add Complete
</cfoutput>
Structure functions
You can use the following functions to create and manage structures in ColdFusion applications. The table describes
the purpose of each function and provides specific, but limited, information that can assist you in determining whether
to use the function instead of other technique.
All functions except StructDelete throw an exception if a referenced key or structure does not exist.
For more information on these functions, see the CFML Reference.
106
Function
Description
Duplicate
IsStruct
Returns True if the specified variable is a ColdFusion structure or a Java object that implements the
java.util.Map interface.
StructAppend
StructClear
StructCopy
Returns a "shallow" copy of the structure. All embedded objects are references to the objects in the original
structure. The Duplicate function has replaced this function for most purposes.
StructCount
StructDelete
StructFind
Returns the value associated with the specified key in the specified structure. This function is redundant
with accessing structure elements using associative array notation.
StructFindKey
Searches through a structure for the specified key name and returns an array containing data on the found
key or keys.
StructFindValue
Searches through a structure for the specified simple data value (for example, a string or number) and
returns an array containing information on the value location in the structure.
StructGet
Returns a reference to a substructure contained in a structure at the specified path. This function is
redundant with using direct reference to a structure. If you accidentally use this function on a variable that
is not a structure, it replaces the value with an empty structure.
StructInsert
Inserts the specified key-value pair into the specified structure. Unlike a direct assignment statement, this
function generates an error by default if the specified key exists in the structure.
StructIsEmpty
Indicates whether the specified structure contains data. Returns True if the structure contains no data, and
False if it does contain data.
StructKeyArray
StructKeyExists
Returns True if the specified key is in the specified structure. You can use this function in place of the
IsDefined function to check for the existence of variables in scopes that are available as structures.
StructKeyList
StructNew
StructSort
Returns an array containing the key names of a structure in the order determined by the sort criteria.
StructUpdate
Updates the specified key with the specified value. Unlike a direct assignment statement, this function
generates an error if the structure or key does not exist.
About CFScript
CFScript is a language within a language. It is a scripting language that is like JavaScript but is simpler to use. Also,
unlike JavaScript, CFScript only runs on the ColdFusion server; it does not run on the client system. CFScript code can
use all the ColdFusion functions and expressions, and has access to all ColdFusion variables that are available its scope.
107
CFScript provides a compact and efficient way to write ColdFusion logic. Typical uses of CFScript include the
following:
108
Using CFScript
<cfscript>
if (IsDefined("Form.submit")) {
if ((Form.lastname NEQ "") AND (Form.department NEQ "")) {
employee=StructNew();
employee.firstname=Form.firstname;
employee.lastname=Form.lastname;
employee.email=Form.email;
employee.phone=Form.phone;
employee.department=Form.department;
WriteOutput("Adding #Form.firstname# #Form.lastname# <br>");
}
else
WriteOutput("You must enter a Last Name and Department.<br>");
}
</cfscript>
Equivalent in CFScript
cfabort
abort
cfcomponent
component
cfcontinue
continue
cfdirectory
writedump
cfexit
exit
cffinally
finally
cfimport
import
cfinclude
include
cfinterface
interface
cflocation
location
cflog
writelog
cfparam
param
cfprocessingdirective
pageencoding
cfproperty
property
cfrethrow
rethrow
cfthread
thread
109
Tag
Equivalent in CFScript
cfthrow
throw
cftrace
trace
cftransaction
transaction
ftp
cfftp
http
cfhttp
cfmail
cfpdf
query
cfquery
storedproc
cfstoredproc
For details of the Script Functions, see the section Script Functions Implemented as CFCs in the CFML Reference.
CFScript equivalent
cfabort
abort
cfbreak
break. CFScript also has a continue statement that has no equivalent CFML tag.
cfcase
case
cfcatch
catch
cfcomponent
component
cfcontinue
continue
cfcookie
Direct assignment of Cookie scope memory-only variables. You cannot use direct
assignment to set persistent cookies that are stored on the user system.
cfdefaultcase
default
110
Tag
CFScript equivalent
cfdirectory
writedump
cfelse
else
cfelseif
elseif
cfexit
exit
cffile
cffinally
finally
cffunction
function
cfimage
cfif
if
cfimport
import
Import in cfscript is only equivalent of <cfimport path="">. You cannot use
<cfimport taglib=""> in cfscript.
cfinclude
include
cfinterface
interface
cflocation
location
cflock
lock
cflog
writelog
cfloop
Structure cfloop: for in loop. (There is no equivalent for queries, lists, or objects.)
cfobject
createobject, new
cfoutput
writeoutput
cfparam
param
cfprocessingdirective
pageencoding
cfproperty
property
cfrethrow
rethrow
cfreturn
return
cfsavecontent
savecontent
cfset
var
var x =1; is equivalent of <cfset var x =1>
switch
111
Tag
CFScript equivalent
cfthread
thread
cfthrow
throw
cftrace
trace
cftransaction
transaction
cftry
try
Example
The following example loops through a query in CFScript:
...
<cfscript>
// Loop through the qGetEmails RecordSet
for (x = 1; x <= qGetEmails.RecordCount; x=x+1) {
This_id = qGetEmails.Emails_id[x];
This_Subject = qGetEmails.Subject[x];
This_RecFrom = qGetEmails.RecFrom[x];
This_SentTo = qGetEmails.SentTo[x];
This_dReceived = qGetEmails.dReceived[x];
This_Body = qGetEmails.Body[x];
... // More code goes here.
}
</cfscript>
Reserved words
In addition to the names of ColdFusion functions and words reserved by ColdFusion expressions (such as NOT, AND,
IS, and so on), the following words are reserved in CFScript. Do not use these words as variables or identifiers in your
scripting code:
break
do
import
var
case
else
in
while
catch
finally
interface
try
for
pageencoding
continue
function
return
default
if
switch
Script functions
For a list of script functions, see Script Functions added in ColdFusion 9 on page 109.
Identifying CFScript
You enclose CFScript regions inside <cfscript> and </cfscript> tags. No other CFML tags are allowed inside a
cfscript region. The following lines show a minimal script:
112
<cfscript>
a = 2;
</cfscript>
Variables
CFScript variables can be of any ColdFusion type, such as numbers, strings, arrays, queries, and objects. The CFScript
code can read and write any variables that are available in the page that contains the script. These variables include all
shared scopes, such as session, application, and server variables.
CFML operator
CFScript operator
CFML operator
==
EQ
!=
NEQ
<
LT
<=
LTE
>
GT
>=
GTE
For information about CFML expressions, operators, and functions, see Using Expressions and Number Signs on
page 64.
Statements
CFScript supports the following statements:
assignment
for-in
try-catch
function call
while
if-else
do-while
switch-case-default
break
for
continue
Statement blocks
Curly bracket characters ({ and }) group multiple CFScript statements so that they are treated as a single unit or
statement. This syntax enables you to create code blocks in conditional statements, such as the following:
113
if(score GT 0)
{
result = "positive";
Positives = Positives + 1;
}
In this example, both assignment statements are executed if the score is greater than 0. If they were not in the code
block, only the first line would execute.
You do not have to place curly bracket characters on their own lines in the code. For example, you could place the open
curly bracket in the preceding example on the same line as the if statement, and some programmers use this style.
However, putting at least the ending brace on its own line makes it easier to read the code and separate code blocks.
Comments
CFScript has two forms of comments: single line and multiline.
A single-line comment begins with two forward slashes (//) and ends at the line end; for example:
//This is a single-line comment.
//This is a second single-line comment.
A multiline comment starts with a /* marker and continues until it reaches a */ marker; for example:
/*This is a multiline comment.
You do not need to start each line with a comment indicator.
This line is the last line in the comment. */
Comments do not have to start at the beginning of a line. They can follow active code on a line. For example, the
following line is valid:
MyVariable = 12; // Set MyVariable to the default value.
The end of a multiline comment can be followed on the same line by active code. For example, the following line is
valid, although it is poor coding practice:
End of my long comment */ foo = "bar";
You can use multiline format for a comment on a single line, for example:
/*This is a single-line comment using multiline format. */
CFScript uses ColdFusion expressions, which are not a superset or a subset of JavaScript expressions. In particular,
ColdFusion expressions do not support bitwise operators, and the ColdFusion MOD or % operator operates
differently from the corresponding JavaScript % operator: In ColdFusion, the operator does integer arithmetic and
ignores fractional parts. ColdFusion expressions also support the EQV, IMP, CONTAINS, and DOES NOT
CONTAIN operators that are not supported in JavaScript.
Variable declarations (var keyword) are only used in user-defined functions and threads.
CFScript is not case sensitive.
114
All statements end with a semicolon, and line breaks in the code are ignored.
Assignments are statements, not expressions, and therefore cannot be used in situations that require evaluating the
assignment operation.
CFScript limitation
You cannot include ColdFusion tags in CFScript. However, you can include cfscript blocks inside other ColdFusion
tags, such as cfoutput.
You can use ColdFusion function calls, including UDFs, directly in CFScript. For example, the following line is a valid
CFScript statement:
StructInsert(employee,"lastname",FORM.lastname);
if and else statements, which serve the same purpose as the cfif, cfelseif, and cfelse tags
switch, case, and default statements, which are the equivalents of the cfswitch, cfcase, and cfdefaultcase tags
115
if(score GT 1)
result = "positive";
else
result = "negative";
CFScript does not include an elseif statement. However, you can use an if statement immediately after an else
statement to create the equivalent of a cfelseif tag, as the following example shows:
if(score GT 1)
result = "positive";
else if(score EQ 0)
result = "zero";
else
result = "negative";
As with all conditional processing statements, you can use curly brackets to enclose multiple statements for each
condition, as follows:
if(score GT 1) {
result = "positive";
message = "The result was positive.";
}
else {
result = "negative";
message = "The result was negative.";
}
Note: Often, you can make your code clearer by using braces even where they are not required.
Using switch and case statements
The switch statement and its dependent case and default statements have the following syntax:
switch (expression) {
case constant: [case constant:]... statement(s) break;
[case constant: [case constant:]... statement(s) break;]...
[default: statement(s)] }
You cannot mix Boolean and numeric constant values in a switch statement.
Each constant value must be a constant (that is, not a variable, a function, or other expression).
Multiple caseconstant: statements can precede the statement or statements to execute if any of the cases are true.
This lets you specify several matches for one code block.
The break statement at the end of the case statement tells ColdFusion to exit the switch statement. ColdFusion
does not generate an error message if you omit a break statement. However, if you omit it, ColdFusion executes all
the statements in the following case statement, even if that case is false. In nearly all circumstances, this is not what
you want to do.
You can have only one default statement in a switch statement block. ColdFusion executes the statements in the
default block if none of the case statement constants equals the expression value.
116
The default statement does not have to follow all case statements, but it is good programming practice to do so.
If any case statements follow the default statement, you must end the default block code with a break
statement.
The default statement is not required. However, use one if the case constants do not include all possible values
of the expression.
The following switch statement takes the value of a name variable:
1 If the name is John or Robert, it sets both the male variable and the found variable to True.
2 If the name is Mary, it sets the male variable to False and the found variable to True.
3 Otherwise, it sets the found variable to False.
switch(name) {
case "John": case "Robert":
male=True;
found=True;
break;
case "Mary":
male=False;
found=True;
break;
default:
found=False;
} //end switch
For
While
Do-while
For-in
CFScript also includes the continue and break statements that control loop processing.
Using for loops
The for loop has the following format:
for (initial-expression; test-expression; final-expression) statement
117
Empty
Note: The test expression is re-evaluated before each repeat of the loop. If code inside the loop changes any part of the test
expression, it can affect the number of iterations in the loop.
The statement can be a single semicolon terminated statement or a statement block in curly brackets.
When ColdFusion executes a for loop, it does the following:
1 Evaluates the initial expression.
2 Evaluates the test-expression.
3 If the test-expression is False, exits the loop and processing continues following the statement.
For loops are most commonly used for processing in which an index variable is incremented each time through the
loop, but it is not limited to this use.
The following simple for loop sets each element in a 10-element array with its index number.
for(index=1;
index LTE 10;
index = index + 1)
a[index]=index;
The use of curly brackets to group multiple statements into a single block.
An empty condition statement. All loop control logic is in the statement block.
<cfscript>
strings=ArrayNew(1);
ArraySet(strings, 1, 10, "lock");
strings[5]="key";
indx=0;
for( ; ; ) {
indx=indx+1;
if(Find("key",strings[indx],1)) {
WriteOutput("Found key at " & indx & ".<br>");
break;
}
else if (indx IS ArrayLen(strings)) {
WriteOutput("Exited at " & indx & ".<br>");
break;
}
}
</cfscript>
This example shows one important issue that you must remember when creating loops: always ensure that the loop
ends. If this example lacked the elseif statement, and there was no key in the array, ColdFusion would loop forever
or until a system error occurred; you would have to stop the server to end the loop.
118
The example also shows two issues with index arithmetic: in this form of loop you must make sure to initialize the
index, and keep track of where the index is incremented. In this case, because the index is incremented at the top of
the loop, initialize it to 0 so it becomes 1 in the first loop.
Using while loops
The while loop has the following format:
while (expression) statement
brackets.
b Returns to step 1.
As with other loops, make sure that at some point the whileexpression is False and be careful to check your index
arithmetic.
Using do-while loops
The do-while loop is like a while loop, except that it tests the loop condition after executing the loop statement block.
The do-while loop has the following format:
do statement while (expression);
brackets.
2 Evaluates the expression.
3 If the expression is true, it returns to step 1.
119
Because the loop index increment follows the array value assignment, the example initializes the loop variable to 1 and
tests to make sure that it is less than or equal to 10.
The following example generates the same results as the previous two examples, but it increments the index before
assigning the array value. As a result, it initializes the index to 0, and the end condition tests that the index is less than 10.
a = ArrayNew(1);
loop = 0;
do {
loop = loop + 1;
a[loop] = loop * 5;
}
while (loop LT 10);
The variable can be any ColdFusion identifier; it holds each structure key name as ColdFusion loops through the
structure. The structure must be the name of an existing ColdFusion structure. The statement can be a single semicolon
terminated statement or a statement block in reference.
The following example creates a structure with three elements. It then loops through the structure and displays the
name and value of each key. Although the curly brackets are not required here, they make it easier to determine the
contents of the relatively long WriteOutput function. In general, you can make structured control flow, especially
loops, clearer by using curly brackets.
myStruct=StructNew();
myStruct.productName="kumquat";
mystruct.quality="fine";
myStruct.quantity=25;
for (keyName in myStruct) {
WriteOutput("myStruct." & Keyname & " has the value: " &
myStruct[keyName] &"<br>");
}
Note: Unlike the cfloop tag, CFScript for-in loops do not provide built-in support for looping over queries and lists.
Using continue and break statements
The continue and break statements enable you to control the processing inside loops:
The continue statement tells ColdFusion to skip to the beginning of the next loop iteration.
120
Using continue
The continue statement ends the current loop iteration, skips any code following it in the loop, and jumps to the
beginning of the next loop iteration. For example, the following code loops through an array and displays each value
that is not an empty string:
for ( loop=1; loop LE 10; loop = loop+1) {
if(a[loop] EQ "") continue;
WriteOutput(loop);
}
(To test this code snippet, you must first create an array, a, with 10 or more elements, some of which are not empty
strings.)
The continue statement is useful if you loop over arrays or structures and you want to skip processing for array
elements or structure members with specific values, such as the empty string.
Using break
The break statement exits the current loop or case statement. Processing continues at the next CFScript statement.
You end case statement processing blocks with a break statement. You can also use a test case with a break statement
to prevent infinite loops, as shown in the following example. This script loops through an array and prints the array
indexes that contain the value key. It uses a conditional test and a break statement to make sure that the loop ends
when at the end of the array.
strings=ArrayNew(1);
ArraySet(strings, 1, 10, "lock");
strings[5]="key";
strings[9]="key";
indx=0;
for( ; ; ) {
indx=indx+1;
if(Find("key",strings[indx],1)) {
WriteOutput("Found a key at " & indx & ".<br>");
}
else if (indx IS ArrayLen(strings)) {
WriteOutput("Array ends at index " & indx & ".<br>");
break;
}
}
121
Example
public String foo(array a)
{
for(var item in a)
{
writedump(item);
}
}
For arrays example, see for-in construct (for arrays) on page 120.
Basic Syntax
Syntax for defining a component is as follows:
/**
* ColdFusion treats plain comment text as a hint.
* You can also use the @hint metadata name for hints.
* Set metadata, including, optionally, attributes, (including custom
* attributes) in the last entries in the comment block, as follows:
*@metadataName metadataValue
...
*/
component attributeName="attributeValue" ... {
body contents
}
122
/**
* Simple Component.
*/
component {
/**
* Simple function.
*/
public void function foo() {
WriteOutput("Method foo() called<br>");
}
}
When you define a component entirely in CFScript, you do not have to use a cfscript tag on the page. In this case,
the component keyword can be preceded only by comments (including metadata assignments) and import operators.
Adobe recommends this format as a best practice. You specify component properties as follows:
/**
/*@default defaultValue
* @attrib1Name attrib1Value
* ...
*/
property [type]propName;
If the type precedes the property name, you do not need to use the "type" keyword, only the name of the specific type.
In either format, you must set the name attribute value. All other property attributes, such as type, are optional. As
with cfproperty tags, place the property operators at the top of the component definition, immediately following the
opening brace.
The syntax to define a function is similar to the component definition:
/**
*Comment text, treated as a hint.
*Set metadata, including, optionally, attributes, in the last entries
*in the comment block, as follows:
*@metadataName metadataValue
...
*/
access returnType function functionName(arg1Type arg1Name="defaultValue1"
arg1Attribute="attributeValue...,arg2Type
arg2Name="defaultValue2" arg2Attribute="attributeValue...,...)
functionAttributeName="attributeValue" ... {
body contents
}
You specify all function arguments, including the argument type, default value, and attributes in the function
definition.
The following example shows a function definition:
/**
* @hint "This function displays its name and parameter."
*/
public void function foo(String n1=10)
description="does nothing" hint="overrides hint" (
WriteOutput("Method foo() called<br> Parameter value is " & n1);
}
Specifying the required keyword makes the argument mandatory. If the required keyword is not present then the
argument becomes optional.
123
For example:
public function funcname(required string argument1)
Interface definitions follow the same pattern as components, with the same general rules and limitations that apply to
the interfaces you define using cfinterface tags. The following simple code defines an interface with a single function
that takes one string argument, with a default argument value of "Hello World!":
interface {
function method1(string arg1="Hello World!");
function method2 (string arg1="Goodbye World!");
...
}
The following example shows the definition of a simple component with a single function:
/**
* Component defined in CFScript
* @output true
*/
component extends="component_01" {
/**
* Function that displays its arguments and returns a string.
* @returnType string
*/
public function method_03(argOne,argTwo) {
WriteOutput("#arguments.argOne# ");
WriteOutput("#arguments.argTwo# ");
return("Arguments written.");
}
}
Setting attributes
The definition syntax provides two ways to set attributes:
At the end of a comment that immediately precedes the element, in the following format
/**
*Comment
*@attributeName1 attributeValue
*@attributeName2 attributeValue
*...
*/
In the element declaration using standard attribute-value assignment notation, as in the following line:
component extends="component_01"
Attribute values set in the element declaration take precedence over the values set in the comment section. Therefore,
if you set an attribute, such as a hint in both locations, ColdFusion ignores the value in the comment section and uses
only the one in the element declaration.
124
// this is a component
/**
*@hint "this is a hint for component"
*/
component displayname="My Component" {
pageencoding "Cp1252" ;
//
// The rest of the component definition goes here.
//
}
Note: Currently, you cannot use CFScript to specify the suppresswhitespace processing directive.
"custom value".
Example
custom.cfm
cfscript>
writeoutput(new custom().foo(10));
</cfscript>
custom.cfc
125
/**
* custom metadata for a cfc defined using annotation as well as key-value pairs
* @cfcMetadata1 "cfc metadata1"
*/
component cfcMetadata2 = "cfc metadata2"
{
/**
* custom metadata for a property defined using annotation as well as key-value
pairs
* @propMetadata1 "property metadata1"
*/
property type="numeric" name="age" default="10" propMetadata2="property
metadata2";
/**
* custom metadata for a function/argument using both annotation and key-value pairs
* @arg1.argmdata1 "arg metadata1"
* output true
* @fnMetadata1 "function metadata1"
*/
public string function foo(required numeric arg1=20 argmdata2="arg metadata2")
fnMetadata2="function metadata2"
{
writedump(getmetadata(this));
return arg1;
}
}
For more information about function local scope see Using ColdFusion Variables on page 38.
throw
writedump
126
writelog
location
trace
You can call these functions by passing the argument as name=value pairs or positional notations. For positional
notations, the sequence of arguments must be followed. The sequence of arguments for each construct is mentioned
in the CFML Reference Guide.
Example of passing arguments as name=value pair:
<cfscript>
writedump(var=myquery, label="query", show="name", format = "text");
</cfscript>
You do not need to specify all the parameters while using positional arguments. For instance, if you want to specify
the first and third argument, you can add an empty value for the second argument. The exception to this usage is when
there is a boolean type for the second argument where you have to specify true or false.
Note: You cannot mix positional and named arguments while calling a function. For example, if you need to use only the
var and output attributes with the writedump construct, you can use writedump(myquery,html).
Quotation marks are optional for most paths. Surround the path in quotation marks if any directory or the CFC name
has a hyphen.
The cfimport tag now supports importing CFCs and takes a path attribute to specify the path to the CF file to import.
Use the import function or cfimport tag with a path attribute on top of the page only. Using them elsewhere has the
same effect as putting them on top of the page. Therefore, standard coding practice places the import tags or operators
at the top of the file. The cfimport tag can precede a cfcomponent tag. The import CFScript statement must follow the
component statement.
127
The ColdFusion Administrator Sever Settings > Caching page now has a Component Cache option, and a Clear
Component Cache button. To prevent ColdFusion from caching resolved component paths, clear the Component
Cache option. Click the Clear Component Cache button to remove any resolved component paths from the cache.
Note: In all cases, ColdFusion automatically imports the com.adobe.coldfusion.* name space for CFCs. You do not have
to import this path explicitly.
The new operator creates an instance of a CFC. It is equivalent to the cfobject tags and CreateObject function. You can
use new as a CFScript operator, or in assignment statements outside a CFScript block, such as in a cfset tag. ColdFusion
does not have a corresponding cfnew tag.
The new operation has the following syntax:
cfObject=new cfcPath(constructorParam1,...)
or
cfObject=new cfcPath(arg1=constructorParam1Value,...)
If the folder name or CFC name has hyphen, use the following syntax:
cfObject=new "cfc-path"(constructorParam1,...)
If you use the import operator to import the directory that contains the CFC, the cfcPath value is the CFC filename.
The constructor parameters can be positional or in name="value" format. When you use the new operator, ColdFusion
does the following:
1 Looks for an initmethod constructor method in the CFC. If found, ColdFusion instantiates the component and
runs initmethod.
2 If it does not find an initmethod constructor method, it looks for an init constructor method. If found, ColdFusion
Note: Only the new operator automatically invokes the initmethod or init function. The new operator returns the
value returned by init or initmethod and if the return is void it returns the instance of the CFC. The cfobject tags
and the CreateObject function do not invoke the function and you must explicitly call any custom initialization code.
Handling exceptions
ColdFusion provides two statements for exception handling in CFScript: try and catch. These statements are
equivalent to the CFML cftry and cfcatch tags.
Note: For a discussion of exception handling in ColdFusion, see Handling Errors on page 275.
128
try {
Code where exceptions will be caught
}
catch(exceptionType exceptionVariable) {
Code to handle exceptions of type exceptionType
that occur in the try block
}
...
catch(exceptionTypeN exceptionVariableN) {
Code to handle exceptions of type
exceptionTypeN that occur in the try block
}
finally {
Code that will execute whether there is an exception or not.
}
Note: In CFScript, catch and finally statements follow the try block; you do not place them inside the try block. This
structure differs from that of the cftry tag, which must include the cfcatch and cffinally tags in its body.
When you have a try statement, you must have a catch statement. In the catch block, the exceptionVariable variable
contains the exception type. This variable is the equivalent of the cfcatch tag cfcatch.Type built-in variable.
The finally block is optional. Its code always runs, and runs after the code in the try block and any catch block.
CFScript example
The following example uses these CFScript features:
Variable assignment
Function calls
For loops
If-else statements
129
WriteOutput functions
Switch statements
The example uses CFScript without any other ColdFusion tags. It creates a structure of course applicants. This
structure contains two arrays; the first has accepted students, the second has rejected students. The script also creates
a structure with rejection reasons for some (but not all) rejected students. It then displays the accepted applicants
followed by the rejected students and their rejection reasons.
<html>
<head>
<title>CFScript Example</title>
</head>
<body>
<cfscript>
//Set the variables
acceptedApplicants[1] = "Cora Cardozo";
acceptedApplicants[2] = "Betty Bethone";
acceptedApplicants[3] = "Albert Albertson";
rejectedApplicants[1] = "Erma Erp";
rejectedApplicants[2] = "David Dalhousie";
rejectedApplicants[3] = "Franny Farkle";
applicants.accepted=acceptedApplicants;
applicants.rejected=rejectedApplicants;
rejectCode=StructNew();
rejectCode["David Dalhousie"] = "score";
rejectCode["Franny Farkle"] = "too late";
//Sort and display accepted applicants
ArraySort(applicants.accepted,"text","asc");
WriteOutput("The following applicants were accepted:<hr>");
for (j=1;j lte ArrayLen(applicants.accepted);j=j+1) {
WriteOutput(applicants.accepted[j] & "<br>");
}
WriteOutput("<br>");
//sort and display rejected applicants with reasons information
ArraySort(applicants.rejected,"text","asc");
WriteOutput("The following applicants were rejected:<hr>");
for (j=1;j lte ArrayLen(applicants.rejected);j=j+1) {
130
applicant=applicants.rejected[j];
WriteOutput(applicant & "<br>");
if (StructKeyExists(rejectCode,applicant)) {
switch(rejectCode[applicant]) {
case "score":
WriteOutput("Reject reason: Score was too low.<br>");
break;
case "late":
WriteOutput("Reject reason: Application was late.<br>");
break;
default:
WriteOutput("Rejected with invalid reason code.<br>");
} //end switch
} //end if
else {
WriteOutput("Reject reason was not defined.<br>");
} //end else
WriteOutput("<br>");
} //end for
</cfscript>
Description
<cfscript>
//Set the variables
acceptedApplicants[1] = "Cora Cardozo";
acceptedApplicants[2] = "Betty Bethone";
acceptedApplicants[3] = "Albert Albertson";
rejectedApplicants[1] = "Erma Erp";
rejectedApplicants[2] = "David Dalhousie";
rejectedApplicants[3] = "Franny Farkle";
applicants.accepted=acceptedApplicants;
applicants.rejected=rejectedApplicants;
rejectCode=StructNew();
rejectCode["David Dalhousie"] = "score";
rejectCode["Franny Farkle"] = "too late";
ArraySort(applicants.accepted,"text","asc");
WriteOutput("The following applicants were accepted:<hr>");
for (j=1;j lte ArrayLen(applicants.accepted);j=j+1) {
WriteOutput(applicants.accepted[j] & "<br>");
}
WriteOutput("<br>");
ArraySort(applicants.rejected,"text","asc");
WriteOutput("The following applicants were rejected:<hr>");
131
Code
Description
if (StructKeyExists(rejectCode,applicant)) {
switch(rejectCode[applicant]) {
case "score":
WriteOutput("Reject reason: Score was too low.<br>");
break;
case "late":
WriteOutput("Reject reason: Application was late.<br>");
break;
default:
WriteOutput("Rejected with invalid reason code.<br>");
} //end switch
} //end if
else {
WriteOutput("Reject reason was not defined.<br>");
} //end else
WriteOutput("<br>");
} //end for
</cfscript>
REFind
REFindNoCase
REMatch
REMatchNoCase
REReplace
REReplaceNoCase
Regular expressions used in the cfinput and cftextinput tags are JavaScript regular expressions, which have a
slightly different syntax than ColdFusion regular expressions. For information on JavaScript regular expressions, see
Building Dynamic Forms with cfform Tags on page 722.
You must provide the exact string pattern to match. If the exact pattern is not found, Find returns an index of 0.
Because you must specify the exact string pattern to match, matches for dynamic data can be difficult, if not impossible,
to construct.
132
The next example uses a regular expression to perform the same search. This example searches for the first occurrence
in the search string of any string pattern that consists entirely of uppercase letters enclosed by spaces:
<cfset IndexOfOccurrence=REFind(" [A-Z]+ ", "Some BIG string")>
<!--- The value of IndexOfOccurrence is 5 --->
The regular expression " [A-Z]+ " matches any string pattern consisting of a leading space, followed by any number of
uppercase letters, followed by a trailing space. Therefore, this regular expression matches the string " BIG " and any
string of uppercase letters enclosed in spaces.
By default, the matching of regular expressions is case-sensitive. You can use the REFindNoCase and
REReplaceNoCase functions for case-insensitive matching.
Because you often process large amounts of dynamic textual data, regular expressions are invaluable in writing
complex ColdFusion applications.
REFind
REFindNoCase
REMatch
REMatchNoCase
REReplace
REReplaceNoCase
REFind and REFindNoCase use a regular expression to search a string for a pattern and return the string index where
it finds the pattern. For example, the following function returns the index of the first instance of the string " BIG ":
<cfset IndexOfOccurrence=REFind(" BIG ", "Some BIG BIG string")>
<!--- The value of IndexOfOccurrence is 5 --->
To find the next occurrence of the string " BIG ", you must call the REFind function a second time. For an example of
iterating over a search string to find all occurrences of the regular expression, see Returning matched subexpressions
on page 141.
REReplace and REReplaceNoCase use regular expressions to search through a string and replace the string pattern
that matches the regular expression with another string. You can use these functions to replace the first match, or to
replace all matches.
For detailed descriptions of the ColdFusion functions that use regular expressions, see the CFML Reference.
In this example, REFind must match the exact string pattern " BIG ".
To use the full power of regular expressions, combine literal characters with character sets and special characters, as in
the following example:
133
The literal characters of the regular expression consist of the space characters at the beginning and end of the regular
expression. The character set consists of that part of the regular expression in brackets. This character set specifies to
find a single uppercase letter from A to Z, inclusive. The plus sign (+) after the brackets is a special character specifying
to find one or more occurrences of the character set.
If you removed the + from the regular expression in the previous example, " [A-Z] " matches a literal space, followed
by any single uppercase letter, followed by a single space. This regular expression matches " B " but not " BIG ". The
REFind function returns 0 for the regular expression, meaning that it did not find a match.
You can construct complicated regular expressions containing literal characters, character sets, and special characters.
Like any programming language, the more you work with regular expressions, the more you can accomplish with
them. The examples here are fairly basic. For more examples, see Regular expression examples on page 143.
134
The regular expression [T]* can match empty strings. It first matches the empty string before H in Hello. The
ALL argument tells REReplace to replace all instances of an expression. The empty string before e is matched, and
so on, until the empty string before o is matched.
This result might be unexpected. The workarounds for these types of problems are specific to each case. In some cases
you can use [T]+, which requires at least one T, instead of [T]*. Alternatively, you can specify an additional pattern
after [T]*.
In the following examples the regular expression has a W at the end:
<cfoutput>
REReplace("Hello World","[T]*W","7","ALL")
#REReplace("Hello World","[T]*W","7","ALL")#<BR>
</cfoutput>
The regular expression "[0-9]{3,}" specifies to match any integer number containing three or more digits: 123,
45678, and so on. However, this regular expression does not match a one-digit or two-digit number.
You use the following syntax to find repeating characters:
1 {m,n}
Where m is 0 or greater and n is greater than or equal to m. Match m through n (inclusive) occurrences.
The expression {0,1} is equivalent to the special character ?.
2 {m,}
Where m is 0 or greater. Match at least m occurrences. The syntax {,n} is not allowed.
The expression {1,} is equivalent to the special character +, and {0,} is equivalent to *.
3 {m}
JAVA
135
java
Java
jAva
All other combinations of case
Using subexpressions
Parentheses group parts of regular expressions into subexpressions that you can treat as a single unit. For example, the
regular expression "ha" specifies to match a single occurrence of the string. The regular expression "(ha)+" matches one
or more instances of ha.
In the following example, you use the regular expression "B(ha)+" to match the letter "B" followed by one or more
occurrences of the string "ha":
<cfset IndexOfOccurrence=REFind("B(ha)+", "hahaBhahahaha")>
<!--- The value of IndexOfOccurrence is 5 --->
You can use the special character | in a subexpression to create a logical "OR". You can use the following regular
expression to search for the word "jelly" or "jellies":
<cfset IndexOfOccurrence=REFind("jell(y|ies)", "I like peanut butter and jelly">
<!--- The value of IndexOfOccurrence is 26--->
In some cases, you use a special character as a literal character. For example, if you want to search for the plus sign in
a string, you have to escape the plus sign by preceding it with a backslash:
"\+"
The following table describes the special characters for regular expressions:
Special Character
Description
A backslash followed by any special character matches the literal character itself, that is, the backslash escapes the
special character.
For example, "\+" matches the plus sign, and "\\" matches a backslash.
[]
A one-character character set that matches any of the characters in that set.
For example, "[akm]" matches an a, k, or m. A hyphen in a character set indicates a range of characters; for
example, [a-z] matches any single lowercase letter.
If the first character of a character set is the caret (^), the regular expression matches any character except those
in the set. It does not match the empty string.
For example, [^akm] matches any character except a, k, or m. The caret loses its special meaning if it is not
the first character of the set.
136
Special Character
Description
If the caret is at the beginning of a regular expression, the matched string must be at the beginning of the string
being searched.
For example, the regular expression "^ColdFusion" matches the string "ColdFusion lets you use regular
expressions" but not the string "In ColdFusion, you can use regular expressions."
If the dollar sign is at the end of a regular expression, the matched string must be at the end of the string being
searched.
For example, the regular expression "ColdFusion$" matches the string "I like ColdFusion" but not the string
"ColdFusion is fun."
A character set or subexpression followed by a question mark matches zero or one occurrence of the character
set or subexpression.
For example, xy?z matches either xyz or xz.
A character set or subexpression followed by a plus sign matches one or more occurrences of the character set or
subexpression.
For example, [a-z]+ matches one or more lowercase characters.
A character set or subexpression followed by an asterisk matches zero or more occurrences of the character set or
subexpression.
For example, [a-z]* matches zero or more lowercase characters.
()
Parentheses group parts of a regular expression into subexpressions that you can treat as a single unit.
For example, (ha)+ matches one or more instances of ha.
(?x)
If at the beginning of a regular expression, it specifies to ignore whitespace in the regular expression and lets you
use ## for end-of-line comments. You can match a space by escaping it with a backslash.
For example, the following regular expression includes comments, preceded by ##, that are ignored by
ColdFusion:
reFind("(?x)
one ##first option
|two ##second option
|three\ point\ five ## note escaped spaces
", "three point five")
(?m)
If at the beginning of a regular expression, it specifies the multiline mode for the special characters ^ and $.
When used with ^, the matched string can be at the start of the entire search string or at the start of new lines,
denoted by a linefeed character or chr(10), within the search string. For $, the matched string can be at the end
the search string or at the end of new lines.
Multiline mode does not recognize a carriage return, or chr(13), as a new line character.
The following example searches for the string two across multiple lines:
#reFind("(?m)^two", "one#chr(10)#two")#
This example returns 4 to indicate that it matched two after the chr(10) linefeed. Without (?m), the regular
expression would not match anything, because ^ only matches the start of the string.
The character (?m) does not affect \A or \Z, which always match the start or end of the string, respectively. For
information on \A and \Z, see Using escape sequences on page 137.
137
Special Character
Description
(?i)
If at the beginning of a regular expression for REFind(), it specifies to perform a case-insensitive compare.
For example, the following line would return an index of 1:
#reFind("(?i)hi", "HI")#
If you omit the (?i), the line would return an index of zero to signify that it did not find the regular expression.
(?=...)
If at the beginning of a regular expression, it specifies to use positive lookahead when searching for the regular
expression.
If you prefix a subexpression with this, ColdFusion uses positive lookahead for that subexpression.
Positive lookahead tests for the parenthesized subexpression like regular parenthesis, but does not include the
contents in the match - it merely tests to see if it is there in proximity to the rest of the expression.
For example, consider the expression to extract the protocol from a URL:
<cfset regex = "http(?=://)">
<cfset string = "http://">
<cfset result = reFind(regex, string, 1, "yes")>
mid(string, result.pos[1], result.len[1])
This example results in the string "http". The lookahead parentheses ensure that the "://" is there, but does not
include it in the result. If you did not use lookahead, the result would include the extraneous "://".
Lookahead parentheses do not capture text, so backreference numbering will skip over these groups. For more
information on backreferencing, see Using backreferences on page 139.
(?!...)
If at the beginning of a regular expression, it specifies to use negative lookahead. Negative is just like positive
lookahead, as specified by (?=...), except that it tests for the absence of a match.
Lookahead parentheses do not capture text, so backreference numbering will skip over these groups. For more
information on backreferencing, see Using backreferences on page 139.
(?:...)
If you prefix a subexpression with "?:", ColdFusion performs all operations on the subexpression except that it will
not capture the corresponding text for use with a back reference.
You must be aware of the following considerations when using special characters in character sets, such as [a-z]:
To include a hyphen (-) in the brackets of a character set as a literal character, you cannot escape it as you can other
special characters because ColdFusion always interprets a hyphen as a range indicator. Therefore, if you use a literal
hyphen in a character set, make it the last character in the set.
To include a closing square bracket (]) in the character set, escape it with a backslash, as in [1-3\]A-z]. You do not
have to escape the ] character outside the character set designator.
138
Escape Sequence
Description
\b
When used inside a character set (for example [\b]), it specifies a backspace
\B
Specifies a boundary defined by no transition of character type. For example, two alphanumeric characters in a
row or two nonalphanumeric characters in a row; opposite of \b.
\A
\Z
\n
Newline character
\r
Carriage return
\t
Tab
\f
Form feed
\d
\D
\w
\W
\s
Any whitespace character including tab, space, newline, carriage return, and form feed. Similar to [ \t\n\r\f].
\S
\\x
\ddd
An octal representation of a character, where d is an octal digit, in the form \000 to \377
This code replaces all the spaces with *, producing this string:
Adobe*Web*Site
You can combine character classes with other expressions within a character set. For example, the regular expression
[[:space:]123] searches for a space, 1, 2, or 3. The following example also uses a character class in a regular expression:
<cfset IndexOfOccurrence=REFind("[[:space:]][A-Z]+[[:space:]]",
"Some BIG string")>
<!--- The value of IndexOfOccurrence is 5 --->
139
The following table shows the character classes that ColdFusion supports. Regular expressions using these classes
match any Unicode character in the class, not just ASCII or ISO-8859 characters.
Character class
Matches
:alpha:
:upper:
:lower:
:digit:
:alnum:
:xdigit:
:blank:
Space or a tab.
:space:
:print:
:punct:
:graph:
:cntrl:
Any character not part of the character classes [:upper:], [:lower:], [:alpha:], [:digit:], [:punct:], [:graph:], [:print:], or
[:xdigit:].
:word:
:ascii:
Using backreferences
You use parenthesis to group components of a regular expression into subexpressions. For example, the regular
expression (ha)+ matches one or more occurrences of the string ha.
ColdFusion performs an additional operation when using subexpressions; it automatically saves the characters in the
search string matched by a subexpression for later use within the regular expression. Referencing the saved
subexpression text is called backreferencing.
You can use backreferencing when searching for repeated words in a string, such as the the or is is. The following
example uses backreferencing to find all repeated words in the search string and replace them with an asterisk:
REReplace("There is is coffee in the the kitchen",
"[ ]+([A-Za-z]+)[ ]+\1"," * ","ALL")
Using this regular expression, ColdFusion detects the two occurrences of is as well as the two occurrences of the,
replaces them with an asterisk enclosed in spaces, and returns the following string:
There * coffee in * kitchen
140
You can use the optional fourth parameter to REReplace, scope, to replace all repeated words, as in the following code:
REReplace("There is is a cat in in the kitchen",
"([A-Za-z ]+)\1","\1","ALL")
The next example uses two backreferences to reverse the order of the words "apples" and "pears" in a sentence:
<cfset astring = "apples and pears, apples and pears, apples and pears">
<cfset newString = REReplace("#astring#", "(apples) and (pears)",
"\2 and \1","ALL")>
In this example, you reference the subexpression (apples) as \1 and the subexpression (pears) as \2. The REReplace
function returns the string:
"pears and apples, pears and apples, pears and apples"
Note: To use backreferences in either the search string or the replace string, you must use parentheses within the regular
expression to create the corresponding subexpression. Otherwise, ColdFusion throws an exception.
Using backreferences to perform case conversions in replacement strings
The REReplace and REReplaceNoCase functions support special characters in replacement strings to convert
replacement characters to uppercase or lowercase. The following table describes these special characters:
Special character
Description
\u
\l
\U
\L
\E
End \U or \L.
To include a literal \u, or other code, in a replacement string, escape it with another backslash; for example \\u.
For example, the following statement replaces the uppercase string "HELLO" with a lowercase "hello". This example
uses backreferences to perform the replacement.
REReplace("HELLO", "([[:upper:]]*)", "Don't shout\scream \L\1")
141
This example returns "Hello Mr. Bond". If you did not prohibit the capturing of the Hi/Hello group, the \2
backreference would end up referring to that group instead of " Bond", and the result would be "Hello Mr.ello".
To find all instances of the regular expression, you must call the REFind and REFindNoCase functions multiple times.
Both the REFind and REFindNoCase functions take an optional third parameter that specifies the starting index in the
search string for the search. By default, the starting location is index 1, the beginning of the string.
To find the second instance of the regular expression in this example, you call REFind with a starting index of 8:
<cfset IndexOfOccurrence=REFind(" BIG ", "Some BIG BIG string", 8)>
<!--- The value of IndexOfOccurrence is 9 --->
In this case, the function returns an index of 9, the starting index of the second string " BIG ".
To find the second occurrence of the string, you must know that the first string occurred at index 5 and that the strings
length was 5. However, REFind only returns starting index of the string, not its length. So, you either must know the
length of the matched string to call REFind the second time, or you must use subexpressions in the regular expression.
The REFind and REFindNoCase functions let you get information about matched subexpressions. If you set these
functions fourth parameter, ReturnSubExpression, to True, the functions return a CFML structure with two arrays,
pos and len, containing the positions and lengths of text strings that match the subexpressions of a regular expression,
as the following example shows:
<cfset sLenPos=REFind(" BIG ", "Some BIG BIG string", 1, "True")>
<cfoutput>
<cfdump var="#sLenPos#">
</cfoutput><br>
142
Element one of the pos array contains the starting index in the search string of the string that matched the regular
expression. Element one of the len array contains length of the matched string. For this example, the index of the first
" BIG " string is 5 and its length is also 5. If the regular expression does not occur, the pos and len arrays each contain
one element with a value of 0.
You can use the returned information with other string functions, such as mid. The following example returns that
part of the search string matching the regular expression:
<cfset myString="Some BIG BIG string">
<cfset sLenPos=REFind(" BIG ", myString, 1, "True")>
<cfoutput>
#mid(myString, sLenPos.pos[1], sLenPos.len[1])#
</cfoutput>
Each additional element in the pos array contains the position of the first match of each subexpression in the search
string. Each additional element in len contains the length of the subexpressions match.
In the previous example, the regular expression " BIG " contained no subexpressions. Therefore, each array in the
structure returned by REFind contains a single element.
After executing the previous example, you can call REFind a second time to find the second occurrence of the regular
expression. This time, you use the information returned by the first call to make the second:
<cfset newstart = sLenPos.pos[1] + sLenPos.len[1] - 1>
<!--- subtract 1 because you need to start at the first space --->
<cfset sLenPos2=REFind(" BIG ", "Some BIG BIG string", newstart, "True")>
<cfoutput>
<cfdump var="#sLenPos2#">
</cfoutput><br>
If you include subexpressions in your regular expression, each element of pos and len after element one contains the
position and length of the first occurrence of each subexpression in the search string.
In the following example, the expression [A-Za-z]+ is a subexpression of a regular expression. The first match for the
expression ([A-Za-z]+)[ ]+, is is is.
<cfset sLenPos=REFind("([A-Za-z]+)[ ]+\1",
"There is is a cat in in the kitchen", 1, "True")>
<cfoutput>
<cfdump var="#sLenPos#">
</cfoutput><br>
The entries sLenPos.pos[1] and sLenPos.len[1] contain information about the match of the entire regular expression.
The array elements sLenPos.pos[2] and sLenPos.len[2] contain information about the first subexpression (is).
Because REFind returns information on the first regular expression match only, the sLenPos structure does not
contain information about the second match to the regular expression, "in in".
The regular expression in the following example uses two subexpressions. Therefore, each array in the output structure
contains the position and length of the first match of the entire regular expression, the first match of the first
subexpression, and the first match of the second subexpression.
<cfset sString = "apples and pears, apples and pears, apples and pears">
<cfset regex = "(apples) and (pears)">
<cfset sLenPos = REFind(regex, sString, 1, "True")>
<cfoutput>
<cfdump var="#sLenPos#">
</cfoutput>
143
For a full discussion of subexpression usage, see the sections on REFind and REFindNoCase in the ColdFusion
functions chapter in the CFML Reference.
<b>one</b>
<b>one</b> <b>two</b>
By default, ColdFusion always tries to match the regular expression to the largest string in the search string. The
following code shows the results of this example:
<cfset sLenPos=REFind("<b>(.*)</b>", "<b>one</b> <b>two</b>", 1, "True")>
<cfoutput>
<cfdump var="#sLenPos#">
</cfoutput><br>
Thus, the starting position of the string is 1 and its length is 21, which corresponds to the largest of the two possible
matches.
However, sometimes you might want to override this default behavior to find the shortest string that matches the
regular expression. ColdFusion includes minimal-matching quantifiers that let you specify to match on the smallest
string. The following table describes these expressions:
Expression
Description
*?
minimal-matching version of *
+?
minimal-matching version of +
??
minimal-matching version of ?
{min,}?
{min,max}?
{n}?
If you modify the previous example to use the minimal-matching syntax, the code is as follows:
<cfset sLenPos=REFind("<b>(.*?)</b>", "<b>one</b> <b>two</b>", 1, "True")>
<cfoutput>
<cfdump var="#sLenPos#">
</cfoutput><br>
Thus, the length of the string found by the regular expression is 10, corresponding to the string "<b>one</b>".
144
Expression
Description
[\?&]value=
[A-Z]:(\\[A-Z0-9_]+)+
^[A-Za-z][A-Za-z0-9_]*
([A-Za-z][A-Za-z0-9_]*)(\.[A-Za-z][A-Za-z0-9_]*)?
(\+|-)?[1-9][0-9]*
An integer that does not begin with a zero and has an optional sign.
(\+|-)?[0-9]+(\.[0-9]*)?
A real number.
(\+|-)?[1-9]\.[0-9]*E(\+|-)?[0-9]+
a{2,4}
(ba){3,}
Returns
I Lxxx Jxxxxxx
REReplaceNoCase("cabaret","[A-Z]", "G","ALL")
GGGGGGG
REFindNoCase("a+c","ABCAACCDD")
145
In replacement strings, use \n instead of $n for backreference variables. ColdFusion escapes all $ in the replacement
string.
You do not have to escape backslashes in replacement strings. ColdFusion escapes them, except in case conversion
sequences or escaped versions (for example, \u or \\u).
Embedded modifiers such as (?i) always operate on the entire expression, even if they are inside a group.
\` and the combinations \u\L and \l\U are not supported in replacement strings.
The following Perl statements are not supported:
146
JSP tags from JSP tag libraries. For information on using JSP tags, see Integrating J2EE and Java Elements in CFML
Applications on page 1125.
Java objects, including objects in the Java run-time environment and JavaBeans. For information on using Java
objects, see Integrating J2EE and Java Elements in CFML Applications on page 1125.
Microsoft COM (Component Object Model) objects. For information on using COM objects, see Integrating
COM and CORBA Objects in CFML Applications on page 1170.
CORBA (Common Object Request Broker Architecture) objects. For information on using CORBA objects, see
Integrating COM and CORBA Objects in CFML Applications on page 1170.
Web services. For information on using web services, see Using Web Services on page 1093.
147
The model of an included page is that it is part of your page; it just resides in a separate file. The cfinclude tag cannot
pass parameters to the included page, but the included page has access to all the variables on the page that includes it.
The following image shows this model:
<html>
...
<cfinclude template=
"Template.cfm">
...
</html>
MyPage.cfm
<table>
<tr><td>
Included Text here
</td></tr>
</table>
Template.cfm
MyPage.cfm
<html>
...
<table>
<tr><td>
Included Text here
</td></tr>
</table>
...
</html>
Note: You cannot break CFML code blocks across pages. For example, if you open a cfoutput block in a ColdFusion
page, close the block on the same page; you cannot include the closing portion of the block in an included page.
ColdFusion searches for included files as follows:
The template attribute specifies a path relative to the directory of the calling page.
If the template value is prefixed with a forward slash (/), ColdFusion searches for the included file in directories that
you specify on the Mappings page of the ColdFusion Administrator.
Important: A page must not include itself. Doing so causes an infinite processing loop. To resolve the problem, stop the
ColdFusion server.
Include code in a calling page
1 Create a ColdFusion page named header.cfm that displays your logo. Your page can consist of just the following
lines, or it can include many lines to define an entire header:
<img src="mylogo.gif">
<br>
(For this example to work, you must also place your logo as a GIF file in the same directory as the header.cfm file.)
2 Create a ColdFusion page with the following content:
148
<html>
<head>
<title>Test for Include</title>
</head>
<body>
<cfinclude template="header.cfm">
</body>
</html>
Recommended uses
Consider using the cfinclude tag in the following cases:
If you use the cffunction tag, your function can include CFML tags.
If you write your function using CFScript, you cannot include CFML tags.
You can use UDFs in your application pages just as you use standard ColdFusion functions. When you create a
function for an algorithm or procedure that you use frequently, you can then use the function wherever you need the
procedure, just as you would use a ColdFusion built-in function. For example, the following line calls the function
MyFunct and passes it two arguments:
<cfset returnValue=MyFunct(Arg1, Arg2)>
You can group related functions in a ColdFusion component. For more information, see Using ColdFusion
components on page 149.
As with custom tags, you can easily distribute UDFs to others. For example, the Common Function Library Project at
www.cflib.org is an open-source collection of CFML user-defined functions.
Recommended uses
Typical uses of UDFs include, but are not limited to, the following:
Routines that call functions externally, for example using COM or CORBA, such as routines to determine the space
available on a Windows file system drive
149
You want to pass in arguments, process the results, and return a value. UDFs can return complex values, including
structures that contain multiple simple values.
Recommended uses
Consider using ColdFusion components when doing the following:
Creating web services. (To create web services in ColdFusion, you must use components.)
Creating services that are callable by Flash clients.
Creating libraries of related functions, particularly if they must share data.
Using integrated application security mechanisms based on roles and the requestor location.
Developing code in an object-oriented manner, in which you use methods on objects and can create objects that
extend the features of existing objects.
150
Take arguments.
Have tag bodies with beginning and ending tags.
Do specific processing when ColdFusion encounters the beginning tag.
Do processing that is different from the beginning tag processing when ColdFusion encounters the ending tag.
Have any valid ColdFusion page content in their bodies, including both ColdFusion built-in tags and custom tags
(referred to as nested tags), or even JSP tags or JavaScript.
Be called recursively; that is, a custom tag can, if designed properly, call itself in the tag body.
Return values to the calling page in a common scope or the Variables scope of the calling page, but custom tags do
not return values directly, the way functions do.
Although a custom tag and a ColdFusion page that you include using the cfinclude tag are both ColdFusion pages,
they differ in how they are processed. When a page calls a custom tag, it hands processing off to the custom tag page
and waits until the custom tag page completes. When the custom tag finishes, it returns processing (and possibly data)
to the calling page; the calling page can then complete its processing. The following image shows this process. The
arrows indicate the flow of ColdFusion processing the pages.
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>The date is:</h3>
<cf_now>
</body>
</html>
<cfif IsDefined("Attributes.Type")>
<cfif Attributes.Type IS "Date">
<cfoutput>#DateFormat(Now())#<cfoutput>
<cfelseif Attributes.Type IS "Time">
<cfoutput>#TimeFomat(Now())#<cfoutput>
<cfelse>
<cfoutput>#Now()#<cfoutput>
</cfif>
<cfelse>
<cfoutput>#Now()#</cfoutput>
</cfif>
MyPage.cfm
Now.cfm
If your tag takes a body, end it with the same tag name preceded with a forward slash (/), as follows:
151
</cf_myTag>
For information on using the cfmodule and cfimport tags to call custom CFML tags, see Creating and Using
Custom CFML Tags on page 208.
Recommended uses
ColdFusion custom tags let you abstract complex code and programming logic into simple units. These tags let you
maintain a CFML-like design scheme for your code. You can easily distribute your custom tags and share tags with
others. For example, the ColdFusion Developer Exchange includes a library of custom tags that perform a wide variety
of often-complex jobs; see www.adobe.com/go/learn_cfu_exchange_en.
Consider using CFML custom tags in the following circumstances:
You need a tag-like structure, which has a body and an end tag, with the body contents changing from invocation
to invocation.
You want to associate specific processing with the beginning tag, the ending tag, or both tags.
To use a logical structure in which the tag body uses child tags or subtags. This structure is like the cfform tag,
which uses subtags for the individual form fields.
You do not need a function format in which the calling code uses a direct return value.
Your code must be recursive.
Your functionality is complex.
To distribute your code in a convenient form to others.
If you can create either a UDF or a custom CFML tag for a purpose, first consider creating a UDF because running it
requires less system overhead than using a custom tag.
152
Recommended uses
CFX tags provide one way of using C++ or Java code. However, you can also create Java classes and COM objects and access
them using the cfobject tag. CFX tags, however, provide some built-in features that the cfobject tag does not have:
CFX tags are easier to call in CFML code. You use CFX tags directly in CFML code as you would any other tag, and
you can pass arguments using a standard tag format.
ColdFusion provides predefined classes for use in your Java or C++ code that facilitate CFX tag development. These
classes include support for request handling, error reporting, and query management.
CFX tags are useful in the following circumstances:
You already have existing application functionality written in C++ or Java that you want to incorporate into your
ColdFusion application.
You cannot build the functionality you need using ColdFusion elements.
You want to provide the new functionality in a tag format, as opposed to using the cfobject tag to import native
Java or COM objects.
You want to use the Java and C++ classes provided by ColdFusion for developing your CFX code.
cfinclude tag
Custom tag
UDF
Use subtags.
Component
153
Purpose
cfinclude tag
Custom tag
UDF
Component
Routines that call functions externally, for example using COM or CORBA, including routines to determine the
space available on a Windows file system drive
For information about selecting among user-defined functions, ColdFusion components, and custom tags, see
Creating ColdFusion Elements on page 146.
Note: The Common Function Library Project at www.cflib.org is an open source collection of CFML user-defined
functions.
154
In a ColdFusion component. If you organize your functions in ColdFusion components, you use the functions as
described in Using ColdFusion components on page 189.
On the page where it is called. You can even define it below the place on the page where it is called, but this poor
coding practice can result in confusing code.
On a page that you include using a cfinclude tag. The cfinclude tag must be executed before the function gets
called. For example, you can define all the functions for your applications on a single page and place a cfinclude
tag at the top of pages that use the functions.
On any page that places the function name in a scope common with the page on which you call the function. For
more information on UDF scoping, see Specifying the scope of a function on page 173.
On the Application.cfc or Application.cfm page. For more information, see Designing and Optimizing a
ColdFusion Application on page 235.
For recommendations on selecting where you define functions, see the sections Using Application.cfm and function
include files on page 173 and Specifying the scope of a function on page 173.
The function definition syntax is familiar to anyone who uses JavaScript or most programming languages.
CFScript is efficient for writing business logic, such as expressions and conditional operations.
CFScript function definitions cannot include CFML tags.
The following is a CFScript definition for a function that returns a power of 2:
<cfscript>
function twoPower(exponent) {
return 2^exponent;
}
</cfscript>
For more information on how to use CFScript to define a function, see Defining functions in CFScript on page 154.
155
Function variable
Description
functionName
The name of the function. You cannot use the name of a standard ColdFusion function or any name that
starts with cf. You cannot use the same name for two different function definitions. Function names
cannot include periods.
argName1...
Names of the arguments required by the function. The number of arguments passed into the function
must equal or exceed the number of arguments in the parentheses at the start of the function definition.
If the calling page omits any of the required arguments, ColdFusion generates a mismatched argument
count error.
The body of the function definition must be in curly brackets, even if it is empty.
The following two statements are allowed only in function definitions:
Statement
Description
varvariableName = expression;
Creates and initializes a variable that is local to the function (function variable). This variable
has meaning only inside the function and is not saved between calls to the function. It has
precedence in the function body over any variables with the same name that exist in any
other scopes. You never prefix a function variable with a scope identifier, and the name
cannot include periods. The initial value of the variable is the result of evaluating the
expression. The expression can be any valid ColdFusion expression, including a constant or
even another UDF.
All var statements must be at the top of the function declaration, before any other
statements. Initialize all variables when you declare them. You cannot use the same name
for a function variable and an argument.
Each var statement can initialize only one variable.
Use the var statement to initialize all function-only variables, including loop counters and
temporary variables.
returnexpression;
Evaluates expression (which can be a variable), returns its value to the page that called the
function, and exits the function. You can return any ColdFusion variable type.
In this example, a single line declares the function variable and uses an expression to set it to the value that it returns.
This function can be simplified so that it does not use a function variable, as follows:
function MySum(a,b) {Return a + b;}
Always use curly brackets around the function definition body, even if it is a single statement.
Note: ColdFusion does not COPY any of the function arguments into the local scope of a function. However, if an
unscoped variable is called, it is searched first in argument scope and then local scope.
156
Developers who have a background in CFML or HTML, but no scripting or programming experience are more
familiar with the syntax.
You can include any ColdFusion tag in your function definition. Therefore, you can create a function, for example,
that accesses a database.
For more information on how to use the cffunction tag to define a function, see Defining functions by using the
cffunction tag on page 156.
where brackets ([]) indicate optional arguments. You can have any number of cfargument tags.
The cffunction tag specifies the name you use when you call the function. You can optionally specify other function
characteristics, as the following table describes:
157
Attribute
Description
name
returnType
(Optional) The type of data that the function returns. The valid standard type names are: any, array, binary,
Boolean, date, guid, numeric, query, string, struct, uuid, variableName, xml, and void. If you specify any other
name, ColdFusion requires the argument to be a ColdFusion component with that name.
ColdFusion throws an error if you specify this attribute and the function tries to return data with a type that
ColdFusion cannot automatically convert to the one you specified. For example, if the function returns the result
of a numeric calculation, a returnType attribute of string or numeric is valid, but array is not.
roles
(Optional) A comma-delimited list of security roles that can run this method. If you omit this attribute, ColdFusion
does not restrict user access to the function.
If you use this attribute, the function executes only if the current user is logged in using the cfloginuser tag
and is a member of one or more of the roles specified in the attribute. Otherwise, ColdFusion throws an
unauthorized access exception. For more information on user security, see Securing Applications on page 339.
output
(Optional) Determines how ColdFusion processes displayable output in the function body.
If you do not specify this option, ColdFusion treats the body of the function as normal CFML. As a result, text and
the result of any cfoutput tags in the function definition body are displayed each time the function executes.
If you specify true or yes, the body of the function is processed as if it is in a cfoutput tag. ColdFusion displays
variable values and expression results if you surround the variables and expressions with number signs (#).
If you specify false or no., the function is processed as if it is in a cfsilent tag. The function does not display
any output. The code that calls the function is responsible for displaying any function results.
Use cfargument tags for required function arguments. All cfargument tags must precede any other CFML code in a
cffunction tag body. Therefore, place the cfargument tags immediately following the cffunction opening tag. The
cfargument tag takes the following attributes:
Attribute
Description
name
type
(Optional) The data type of the argument. The type of data that is passed to the function. The valid standard type
names are any, array, binary, Boolean, date, guid, numeric, query, string, struct, uuid, and variableName. If you
specify any other name, ColdFusion requires the argument to be a ColdFusion component with that name.
ColdFusion throws an error if you specify this attribute and the function is called with data of a type that
ColdFusion cannot automatically convert to the one you specified. For example, if the argument type attribute
is numeric, you cannot call the function with an array.
required
(Optional) A Boolean value that specifies whether the argument is required. If set to true and the argument is
omitted from the function call, ColdFusion throws an error. The default value is false. The required attribute is
not required if you specify a default attribute.
Because you do not identify arguments when you call a function, all cfargument tags that specify required
arguments must precede any cfargument tags that specify optional arguments in the cffunction definition.
default
(Optional) The default value for an optional argument if no argument value is passed. If you specify this attribute,
ColdFusion ignores the required attribute.
Note: The cfargument tag is not required for optional arguments. This feature is useful if a function can take an
indeterminate number of arguments. If you do not use the cfargument tag for an optional argument, reference it by
using its position in the Arguments scope array. For more information see Using the Arguments scope as an array on
page 162.
158
The function name must be unique. It must be different from any existing variable, or UDF, except that you can
use the ColdFusion advanced security function names.
You can have a user-defined function with the same name as a built-in function for a CFC but not for CFM.
You cannot use the following names to create user-defined functions:
writedump
writelog
location
throw
trace
The function name must not start with the letters cf in any form. (For example, CF_MyFunction, cfmyFunction,
and cfxMyFunction are not valid UDF names.)
You cannot redefine or overload a function. If a function definition is active, ColdFusion generates an error if you
define a second function with the same name.
You cannot nest function definitions; that is, you cannot define one function inside another function definition.
The function can be recursive, that is, the function definition body can call the function.
The function does not have to return a value.
You can use tags or CFScript to create a UDF. Each technique has advantages and disadvantages.
159
Passing arguments
ColdFusion passes the following data types to the function by value:
Integers
Real numbers
Strings (including lists)
Date-time objects
160
Arrays
As a result, any changes that you make in the function to these arguments do not affect the variable that was used to
call the function, even if the calling code is on the same ColdFusion page as the function definition.
ColdFusion passes queries, structures, and external objects such as COM objects into the function by reference. As a
result, any changes to these arguments in the function also change the value of the variable in the calling code.
For an example of the effects of passing arguments, see Passing complex data on page 160.
161
This technique requires ColdFusion to copy the entire array twice, once when you call the function and once when
the function returns. Doing so is inefficient for large arrays and can reduce performance, particularly if the function
is called frequently.
You can use the return value for other purposes, such as a status variable.
If you do not use the return statement to return the array to the caller, you can pass the array as an element in a
structure and change the array values inside the structure. Then the calling page can access the changed data by using
the structure variable it passed to the UDF.
The following code shows how to rewrite the previous example using an array in a structure. It returns True as a status
indicator to the calling page and uses the structure to pass the array data back to the calling page.
<cfscript>
//Initialize some variables.
//This creates a simple array as an element in a structure.
arrayStruct=StructNew();
arrayStruct.Array=ArrayNew(1);
arrayStruct.Array[1]=2;
arrayStruct.Array[2]=22;
//Define the function.
function doubleOneDArrayS(OneDArrayStruct) {
var i = 0;
for ( i = 1; i LE arrayLen(OneDArrayStruct.Array); i = i + 1)
{ OneDArrayStruct.Array[i] = OneDArrayStruct.Array[i] * 2; }
return True;
}
//Call the function.
Status = doubleOneDArrayS(arrayStruct);
WriteOutput("Status: " & Status);
</cfscript>
</br>
<cfdump var="#arrayStruct#">
Use the same structure element name for the array (in this case Array) in the calling page and the function.
162
You can call this function with a single argument, as in the following line:
<cfset TestFunction(1)>
As a structure
Entry
Value
Entry
Value
Arg1
undefined
Arg2
undefined
In this example, the following functions return the value 2 because the scope contains two defined arguments:
ArrayLen(Arguments)
StructCount(Arguments)
However, the following tests return the value false, because the contents of the second element in the Arguments
scope is undefined.
Isdefined("Arguments.Arg2")
testArg2 = Arguments[2]>
Isdefined("testArg2")
Note: The IsDefined function does not test the existence of array elements. Use the function ArrayContains to search
the array elements.
Using the Arguments scope as an array
The following rules apply to referencing Arguments scope as an array:
If you call the function using unnamed arguments, the array index is the position of the argument in the function
call.
If you use names to pass the arguments, the array indexes correspond to the order in which the arguments are
declared in the function definition.
If you use names to pass arguments, and do not pass all the arguments defined in the function, the Arguments array
has an empty entry at the index corresponding to the argument that was not passed. This rule applies only to
functions created using the cffunction tag.
163
If you use a name to pass an optional argument that is not declared in the function definition, the array index of the
argument is the sum of the following:
Note: Although you can use the Arguments scope as an array, the IsArray(Arguments) function always returns false
and the cfdump tag displays the scope as a structure.
Using the Arguments scope as a structure
The following rule applies when referencing Arguments scope as a structure:
Use the argument names as structure keys. For example, if your function definition includes a Principal argument,
reference the argument as Arguments.Principal.
The following rules are also true, but avoid writing code that uses them. To ensure program clarity, only use the
Arguments structure for arguments that you name in the function definition. Use the Arguments scope as an array
for optional arguments that you do not declare in the function definition.
164
If you do not name an optional argument in the function definition, but do use a name for it in the function call,
use the name specified in the function call For example, if you have an unnamed optional argument and call the
function using the name myOptArg for the argument, you can reference the argument as Arguments.myOptArg
in the function body. This usage, however, is poor programming practice, as it makes the function definition
contents depend on variable names in the code that calls the function.
Using the Arguments scope in CFScript
A function can have optional arguments that you do not have to specify when you call the function. To determine the
number of arguments passed to the function, use the following function:
ArrayLen(Arguments)
When you define a function using CFScript, the function must use the Arguments scope to retrieve the optional
arguments. For example, the following SumN function adds two or more numbers together. It requires two arguments
and supports any number of additional optional arguments. You can reference the first two, required, arguments as
Arg1 and Arg2 or as Arguments[1] and Arguments[2]. Access the third, fourth, and any additional optional
arguments as Arguments[3], Arguments[4], and so on
function SumN(Arg1,Arg2) {
var arg_count = ArrayLen(Arguments);
var sum = 0;
var i = 0;
for( i = 1 ; i LTE arg_count; i = i + 1 )
{
sum = sum + Arguments[i];
}
return sum;
}
With this function, any of the following function calls are valid:
SumN(Value1, Value2)
SumN(Value1, Value2, Value3)
SumN(Value1, Value2, Value3, Value4)
and so on.
The code never uses the Arg1 and Arg2 argument variables directly, because their values are always the first two
elements in the Arguments array and it is simpler to step through the array. Specifying Arg1 and Arg2 in the function
definition ensures that ColdFusion generates an error if you pass the function one or no arguments.
Note: Avoid referring to a required argument in the body of a function by both the argument name and its place in the
Arguments scope array or structure, as doing so can be confusing and makes it easier to introduce errors.
Using the Arguments scope in cffunction definitions
When you define a function using the cffunction tag, you generally reference the arguments directly by name if all
arguments are named in the cfargument tags. If you do use the Arguments scope identifier, follow the rules listed in
About the Arguments scope on page 161.
For more information on using the Arguments scope in functions defined using CFScript, see Using the Arguments
scope in CFScript on page 164.
Function-only variables
In addition to the Arguments scope, each function can have variables that exist only inside the function, and are not
saved between times the function gets called. As soon as the function exits, all the variables in this scope are removed.
165
In CFScript, you create function-only variables with the var statement. Unlike other variables, you never prefix
function-only variables with a scope name.
Using function-only variables
Make sure to use the var statement in CFScript UDFs to declare all function-specific variables, such as loop indexes
and temporary variables that are required only for the duration of the function call. Doing so ensures that these
variables are available inside the function only, and makes sure that the variable names do not conflict with the names
of variables in other scopes. If the calling page has variables of the same name, the two variables are independent and
do not affect each other.
For example, if a ColdFusion page has a cfloop tag with an index variable i, and the tag body calls a CFScript UDF that
also has a loop with a function-only index variable i, the UDF does not change the value of the calling page loop index,
and the calling page does not change the UDF index. So you can safely call the function inside the cfloop tag body.
In general, use the var statement to declare all UDF variables, other than the function arguments or shared-scope
variables, that you use only inside CFScript functions. Use another scope, however, if the value of the variable must
persist between function calls; for example, for a counter that the function increments each time it is called.
Use a shared scope variable, such as an Application or Session scope counter variable.
Use the Request scope to store variables used in the function. For more information, see Using the Request scope
for static variables and constants on page 174.
Create context-specific functions that work directly with caller data if you always synchronize variable names.
Note: If your function must directly change a simple variable in the caller (one that is not passed to the function by
reference), you can place the variable inside a structure argument.
Using arguments
Function arguments can have the same names, but different values, as variables in the caller. Avoid such uses for
clarity, however.
The following rules apply to argument persistence:
Because ColdFusion passes simple variable and array arguments by value, their names and values exist only while
the function executes.
166
Because ColdFusion passes structures, queries, and objects such as COM objects by reference, the argument name
exists only while the function executes, but the underlying data persists after the function returns and can be
accessed by using the variable name of the caller. The variable name of the caller and the argument name can be
different.
Note: If a function must use a variable from another scope that has the same name as a function-only variable, prefix the
external variable with its scope identifier, such as Variables or Form. (However, remember that using variables from
other scopes directly in your code is often poor practice.)
167
Code
Description
<cfscript>
function HelloFriend(Name) {
if (Name is "") WriteOutput("You forgot your name!");
else WriteOutput("Hello " & name &"!"); return "";
}
if (IsDefined("Form.submit"))
HelloFriend(Form.name);
</cfscript>
Use the return value to indicate the function status only. The return value can be a Boolean success/failure
indicator. The return value can also be a status code, for example where 1 indicates success, and various failure types
are assigned known numbers. With this method, the function must set a variable in the caller to the value of a
successful result.
Set a status variable that is available to the caller (not the return variable) to indicate success or failure and any
information about the failure. With this method, the function can return the result directly to the caller. In this
method, the function uses only the return value and structure arguments to pass the status back to the caller.
Each of these methods can have variants, and each has advantages and disadvantages. The technique that you use
depends on the type of function, the application in which you use it, and your coding style.
The following example, which modifies the function used in A user-defined function example on page 171, uses one
version of the status variable method. It provides two forms of error information:
It returns -1, instead of an interest value, if it encounters an error. This value can serve as an error indicator because
you never pay negative interest on a loan.
It also writes an error message to a structure that contains an error description variable. Because the message is in
a structure, it is available to both the calling page and the function.
The TotalInterest function
After changes to handle errors, the TotalInterest function looks like the following. Code that is changed from the
example in A user-defined function example on page 171 is in bold.
168
<cfscript>
function TotalInterest(principal, annualPercent, months, status) {
Var years = 0;
Var interestRate = 0;
Var totalInterest = 0;
principal = trim(principal);
principal = REReplace(principal,"[\$,]","","ALL");
annualPercent = Replace(annualPercent,"%","","ALL");
if ((principal LE 0) OR (annualPercent LE 0) OR (months LE 0)) {
Status.errorMsg = "All values must be greater than 0";
Return -1;
}
interestRate = annualPercent / 100;
years = months / 12;
totalInterest = principal*(((1+ interestRate)^years)-1);
Return DollarFormat(totalInterest);
}
</cfscript>
Description
169
Description
Calls the function. This time, the function requires four arguments,
including the status variable.
If the function returns -1, there must be an error. Displays the message
that the function placed in the status.errorMsg structure key.
<cfelse>
<cfoutput>
Loan amount: #Form.Principal#<br>
Annual percentage rate:
#Form.AnnualPercent#<br>
Loan duration: #Form.Months# months<br>
TOTAL INTEREST: #myInterst#<br>
</cfoutput>
</cfif>
If the function does not return -1, it returns an interest value. Displays
the input values and the function return value.
Using exceptions
UDFs written in CFScript can handle exceptions using the try and catch statements. UDFs written using the
cffunction tag can use the cftry, cfcatch, cfthrow, and cfrethrow tags. Using exceptions corresponds to the way
many functions in other programming languages handle errors, and can be an effective way to handle errors. In
particular, it separates the functional code from the error-handling code, and it can be more efficient than other
methods at runtime, because it does not require testing and branching.
Exceptions in UDFs have the following two dimensions:
170
If the error is recoverable (for example, if the problem is a database time-out where in some cases retrying resolves
the issue), try to recover from the problem.
The code that calls the function and handles the exception looks like the following. The changed lines are in bold.
171
<cftry>
<cfset status = StructNew()>
<cfset myInterest = TotalInterest(Form.Principal, Form.AnnualPercent,
Form.Months, status)>
<cfoutput>
Loan amount: #Form.Principal#<br>
Annual percentage rate: #Form.AnnualPercent#<br>
Loan duration: #Form.Months# months<br>
TOTAL INTEREST: #myInterest#<br>
</cfoutput>
<cfcatch type="InvalidData">
<cfoutput>
#cfcatch.message#<br>
</cfoutput>
</cfcatch>
</cftry>
172
Code
Description
Var years = 0;
Var interestRate = 0;
Var totalInterest = 0;
principal = trim(principal);
principal = REReplace(principal,"[\$,]","","ALL");
annualPercent = Replace(annualPercent,"%","","ALL");
interestRate = annualPercent / 100;
years = months / 12;
totalInterest = principal*
(((1+ interestRate)^years)-1);
Return DollarFormat(totalInterest);
}
173
If you consistently call a small number of UDFs, consider putting their definitions on the Application.cfm page.
If you call UDFs in only a few of your application pages, do not include their definitions in Application.cfm.
If you use many UDFs, place their definitions on one or more ColdFusion pages that contain only UDFs. You can
include the UDF definition page in any page that calls the UDFs.
The next section describes other techniques for making UDFs available to your ColdFusion pages.
You can now use the function from any page in the Request scope by calling Request.MyFunc.
Selecting a function scope
The following table describes the advantages and disadvantages of each function scope:
Scope
Considerations
Application
Makes the function available across all invocations of the application. Access to UDFs in Application scope is
multithreaded and you can execute multiple copies of the UDF at one time.
Request
Makes the function available for the life of the current HTTP request, including in all custom tags and nested
custom tags. This scope is useful if a function is used in a page and in the custom tags it calls, or in nested custom
tags.
Server
Makes the function available to all pages on a single server. In most cases, this scope is not a good choice because
in clustered systems, it only makes the function available on a single server, and all code that uses the function
must be inside a cflock block.
Session
Makes the function available to all pages during the current user session. This scope has no significant advantages
over the Application scope.
174
This way you only include the functions once per request and they are available throughout the life of the request. For
example, create a myFuncs.cfm page that defines your functions and assigns them to the Request scope using syntax
such as the following:
function MyFunc1(Argument1, Argument2)
{ Function definition goes here }
Request.MyFunc1 = MyFunc1
The application page and all custom tags (and nested custom tags) call the functions as follows:
Request.MyFunc1(Value1, Value2)
They are named constants; that is the variable value never changes.
Your application page (and any custom tags) calls the function multiple times.
You can assure that only the function uses the variable names.
In these circumstances, you can improve efficiency and save processing time by defining your functions variables in
the Request scope, rather than the Function scope. The function tests for the Request scope variables and initializes
them if they do not exist. In subsequent calls, the variables exist and the function does not reset them.
The NumberAsString function, written by Ben Forta and available from www.cflib.org, takes advantage of this
technique.
175
<cfscript>
function binop(operation, operand1, operand2)
{ return (operation(operand1, operand2)); }
function sum(addend1, addend2)
{ return addend1 + addend2;}
x = binop(sum, 3, 5);
writeoutput(x);
</cfscript>
You generally use functions that manipulate many rows of a query outside tags that loop over queries. Pass the query
to the function and loop over it inside the function. For example, the following function changes text in a query column
to uppercase. It takes a query name as an argument.
function UCaseColumn(myquery, colName) {
var currentRow = 1;
for (; currentRow lte myquery.RecordCount; currentRow = currentRow + 1)
{
myquery[colName][currentRow] = UCase(myquery[colName][currentRow]);
}
Return "";
}
The following code uses a script that calls the UCaseColumn function to convert all the last names in the GetEmployees
query to uppercase. It then uses cfoutput to loop over the query and display the contents of the column.
<cfscript>
UCaseColumn(GetEmployees, "LastName");
</cfscript>
<cfoutput query="GetEmployees">
#LastName#<br>
</cfoutput>
176
You do not surround the argument to IsCustomFunction in quotation marks, so you can use this function to
determine if function arguments are themselves functions.
Using recursion
A recursive function is a function that calls itself. Recursive functions are useful when an algorithm that repeats the
same operation multiple times using the results of the preceding repetition can solve the problem. Factorial
calculation, used in the following example, is one case where recursion is useful. The Towers of Hanoi game is also
solved using a recursive algorithm.
A recursive function, like looping code, must have an end condition that always stops the function. Otherwise, the
function continues until a system error occurs or you stop the ColdFusion server.
The following example calculates the factorial of a number, that is, the product of all the integers from 1 through the
number; for example, 4 factorial is 4 X 3 X 2 X 1 = 24.
177
function Factorial(factor) {
If (factor LTE 1)
return 1;
else
return factor * Factorial(factor -1);
}
If the function is called with a number greater than 1, it calls itself using an argument one less than it received. It
multiplies that result by the original argument, and returns the result. Therefore, the function keeps calling itself until
the factor is reduced to 1. The final recursive call returns 1, and the preceding call returns 2 * 1, and so on, until all the
initial call returns the end result.
Important: If a recursive function calls itself too many times, it causes a stack overflow. Always test any recursive
functions under conditions that are likely to cause the maximum number of recursions to ensure that they do not cause
a stack overflow.
178
CFCs support introspection; that is, they can provide information about themselves. If you display a component page
directly in an HTML browser, inspect it in the ColdFusion and Adobe Dreamweaver CS3 component browsers, or use
the CFML GetMetadata function, you see information about the component. This information includes its path,
property, methods, and additional information that you can specify using special documentation attributes and tags.
For more information, see Using introspection to get information about components on page 205.
When you use a ColdFusion component, you can invoke a method in the CFC. However, typically, you create an
instance of the CFC, and then invoke methods and refer to properties of the CFC.
The ability to group related methods into a single component, and to group related components into a package
Properties that multiple methods can share
The This scope, a component-specific scope
Inheritance of component methods and properties from a base component, including the use of the Super keyword
Access control
Introspection for CFC methods, properties, and metadata
CFCs have one characteristic that prevents them from being the automatic choice for all code reuse. It takes relatively
more processing time to instantiate a CFC than to process a custom tag. In turn, it takes substantially more time to
process a custom tag than to execute a user-defined function (UDF). However, after a CFC is instantiated, calling a
CFC method has about the same processing overhead as an equivalent UDF. As a result, do not use CFCs in place of
independent, single-purpose custom tags or UDFs. Instead, use CFCs to create bodies of related methods, particularly
methods that share properties.
For more information about UDFs, custom tags, and other ColdFusion code reuse techniques, see Creating
ColdFusion Elements on page 146.
Creating web services
ColdFusion can automatically publish CFC methods as web services. To publish a CFC method as a web service, you
specify the access="remote" attribute in the methods cffunction tag. ColdFusion generates all the required Web
Services Description Language (WSDL) code and exports the CFC methods. For more information on creating web
services in ColdFusion, see Using Web Services on page 1093.
179
Description
cfcomponent
Contains a component definition; includes attributes for introspection. For more information, see Building
ColdFusion components on page 180.
cffunction
Defines a component method (function); includes attributes for introspection. For more information, see
Defining component methods on page 180.
cfargument
Defines a parameter (argument) to a method; includes attributes for introspection. For more information, see
Defining and using method parameters on page 183.
cfproperty
Defines variables for CFCs that provide web services; also use to document component properties. For more
information, see The cfproperty tag on page 188.
Elements of a CFC
A CFC has the following characteristics:
It is a single CFML page with a .cfc filename extension. The component name is the same as the filename. For
example, if the file is myComponent.cfc, the component name is myComponent.
The page is surrounded by a cfcomponent tag. No code can be outside this tag.
The component page defines methods (functions), properties (data), or both. Most CFCs have methods, or
methods and properties, but you can also have a CFC that contains only properties.
180
You use the cffunction tag to define CFC methods. The CFScript function statement can create simple methods,
but it does not provide options to control access to the method, provide metadata, specify a return type, or control
generated output.
You can write code on the component page that is outside cffunction definitions. This code executes when the
CFC is instantiated or whenever you invoke a method of the CFC.
Because component methods are ColdFusion functions, most of their features and coding techniques are identical to
those of user-defined functions. For more information on using the cffunction tag to create functions, see Writing
and Calling User-Defined Functions on page 153. Like other ColdFusion functions, CFC methods can display
information directly by generating output, or can return a value to the code or client that invoked the method.
You use the following cffunction tag attributes only for CFCs:
The displayname and hint attributes, which document the CFC; for more information, see Documenting CFCs
on page 187.
The access attribute, which controls access to the CFC; for more information, see Using access security on
page 204.
181
For detailed reference information on the cffunction tag, see the CFML Reference.
2 Create a ColdFusion page with the following code, and save it as getUTCTime.cfm in the same directory as
tellTime.cfc:
182
<cfscript>
serverTime=now();
utcTime=GetTimeZoneInfo();
utcStruct=structNew();
utcStruct.Hour=DatePart("h", serverTime);
utcStruct.Minute=DatePart("n", serverTime);
utcStruct.Hour=utcStruct.Hour + utcTime.utcHourOffSet;
utcStruct.Minute=utcStruct.Minute + utcTime.utcMinuteOffSet;
if (utcStruct.Minute LT 10) utcStruct.Minute = "0" & utcStruct.Minute;
</cfscript>
In the example, the getUTCTime method definition calls the getUTCTime.cfm file with the cfinclude tag. The
getUTCTime.cfm code calculates the UTC time representation of the current time and populates a structure with
hour and minute values. The method in tellTime.cfc then uses the information in the structure to return the current
UTC time as a string to the calling page. The included page must not include a cfreturn statement.
For information on scopes, see The This scope on page 198 and The Variables scope on page 198.
A useful technique is to define a method named init(), which initializes an instance of a CFC, acting as a constructor.
The init() method can initialize constants and return an instance of the component to the calling page. The following
code illustrates an example of an init() method:
183
<cfcomponent displayname="shoppingCart">
<cffunction name="init" access="public" output="no" returntype="shoppingCart">
<cfargument name="shoppingCartID" type="UUID" required="yes">
<cfset variables.shoppingCartID = arguments.shoppingCartID>
<cfreturn this>
</cffunction>
<!--- Additional methods go here. --->
</cfcomponent>
In this example, the init() method uses the variables scope to make the shopping cart ID available anywhere in the
CFC. For more information about scope, see CFC variables and scope on page 198.
184
Code
Description
<cfcomponent>
Creates the temp parameter of the ctof method. Indicates that it is required and
that the expected value is numeric.
<cfreturn ((temp*9)/5)+32>
</cffunction>
Creates the temp parameter of the ftoc method. Indicates that it is required and
that the expected value is numeric.
<cfreturn ((temp-32)*5/9)>
</cffunction>
</cfcomponent>
Example: tempConversion.cfm
The ColdFusion page tempConversion.cfm is an HTML form in which the user enters the temperature to convert, and
selects the type of conversion to perform. When the user clicks the Submit button, ColdFusion performs the actions
on the processForm.cfm page. The file tempConversion.cfm, which is in the same directory as convertTemp.cfc,
consists of the following:
<cfform action="processForm.cfm" method="POST">
Enter the temperature:
<input name="temperature" type="text"><br>
<br>
Select the type of conversion:<br>
<select name="conversionType">
<option value="CtoF">Celsius to Farenheit</option>
<option value="FtoC">Farenheit to Celsius</option>
</select><br><br>
<input name="submitform" type="submit" value="Submit">
</cfform>
Example: processForm.cfm
The ColdFusion page processForm.cfm calls the appropriate component method, based on what the user entered in
the form on the tempConversion.cfm page. Place it in the same directory as convertTemp.cfc.
185
Description
Executes the code in the cfif block if the user selected Celsius to Fahrenheit
as the conversion type in the form on the tempConversion.cfm page.
<cfinvoke component="convertTemp"
method="ctof"returnvariable="newtemp"arguments
.temp="#form.temperature#">
Displays the temperature that the user entered in the form, the text
"degrees Celsius is," the new temperature value that results from the ctof
method, and the text "degrees Fahrenheit."
Executes the code in the cfelseif block if the user selected Fahrenheit to
Celsius as the conversion type in the form on the tempConversion.cfm page.
<cfinvoke component="converttemp"
method="ftoc"returnvariable="newtemp"
temp=#form.temperature#>
Displays the temperature that the user entered in the form, the text
"degrees Fahrenheit is," the new temperature value that results from the
ftoc method, and the text "degrees Celsius."
</cfif>
To run the example, display the tempConversion.cfm page in your browser. When you enter a value in the text box of
the form, the value is stored in the form.temperature variable. Processing is then performed on the processForm.cfm
page, which refers to the value as form.temperature. When you invoke either method, the cfinvoke tag assigns the
value form.temperature to temp; temp is the argument specified in the cfargument tag of the appropriate method.
The appropriate method in the convertTemp component performs the necessary calculations and returns the new
value as newtemp.
For detailed reference information on the cfargument tag, see the CFML Reference.
186
To access the parameter values in the component method definition, use structure- or array-like notation with the
Arguments scope. The following example refers to the lastName argument as Arguments.lastname; it could also
refer to it as Arguments[1]. In addition, you can access arguments directly using number (#) signs, such as
#lastname#; however, it is better programming practice to identify the scope (for example,
#Arguments.lastname#). Also, you can use Array- or structure-like notation, which lets you loop over multiple
parameters.
For more information on the Arguments scope, see The Arguments scope on page 200.
Define parameters in the component method definition
Create a component with the following contents, and save it as corpQuery.cfc in a directory under your web root
directory:
<cfcomponent>
<cffunction name="getEmp">
<cfargument name="lastName" type="string" required="true"
hint="Employee last name">
<cfset var empQuery="">
<cfquery name="empQuery" datasource="cfdocexamples">
SELECT LASTNAME, FIRSTNAME, EMAIL
FROM tblEmployees
WHERE LASTNAME LIKE '#Arguments.lastName#'
</cfquery>
<!--- Use cfdump for debugging purposes. --->
<cfdump var=#empQuery#>
</cffunction>
<cffunction name="getCat" hint="Get items below specified cost">
<cfargument name="cost" type="numeric" required="true">
<cfset var catQuery="">
<cfquery name="catQuery" datasource="cfdocexamples">
SELECT ItemName, ItemDescription, ItemCost
FROM tblItems
WHERE ItemCost <= #Arguments.cost#
</cfquery>
<!--- Use cfdump for debugging purposes. --->
<cfdump var=#catQuery#>
</cffunction>
</cfcomponent>
The required attributes indicate that the parameters are required, if not, ColdFusion throws an exception.
The Arguments scope provides access to the parameter values.
Providing results
ColdFusion components can provide information in the following ways:
187
You can use either technique, or a combination of both, in your applications. The best technique to use depends on
your applications needs and your coding methodologies. For example, many CFC methods that perform business
logic return the results as a variable, and many CFC methods that display output directly are designed as modular units
for generating output, and do not do business logic.
Displaying output
If you do not specifically suppress output, any text, HTML code, or output that CFML tags generate inside your
method gets returned as generated output to the client that calls the component method. If the client is a web browser,
it displays these results. For example, the following getLocalTime1 component method shows the local time directly
on the page that invokes the method:
<cfcomponent>
<cffunction name="getLocalTime1">
<cfoutput>#TimeFormat(now())#</cfoutput>
</cffunction>
</cfcomponent>
Component methods that are called by using Flash Remoting or as web services cannot use this method to provide
results.
Returning a results variable
In the component method definition, you use the cfreturn tag to return the results to the client as variable data. For
example, the following getLocalTime2 component method returns the local time as a variable to the ColdFusion page
or other client that invokes the method:
<cfcomponent>
<cffunction name="getLocalTime">
<cfreturn TimeFormat(now())>
</cffunction>
</cfcomponent>
The ColdFusion page or other client, such as a Flash application, that receives the result then uses the variable data as
appropriate.
Note: If a CFC is invoked using a URL or by submitting a form, ColdFusion returns the variable as a WDDX packet. A
CFC that is invoked by Flash Remoting, or any other instance of a CFC, must not return the This scope.
You can return values of all data types, including strings, integers, arrays, structures, and instances of CFCs. The
cfreturn tag returns a single variable, as does the return CFScript statement. Therefore, if you want to return more
than one result value at a time, use a structure. If you do not want to display output in a method, use output="false"
in the cffunction tag.
For more information on using the cfreturn tag, see the CFML Reference.
Documenting CFCs
ColdFusion provides several ways to include documentation about your CFCs in your component definitions. The
documentation is available when you use introspection to display information about the CFC or call the GetMetadata
or GetComponentMetaData function to get the components metadata. You can use the following tools for
documenting CFCs:
188
For information on displaying the information, see Using introspection to get information about components on
page 205.
The displayname and hint attributes
The cfcomponent, cffunction, cfargument, and cfproperty tags have displayname and hint attributes.
The displayname attribute lets you provide a more descriptive name for a component, attribute, method, or property.
When you use introspection, this attribute appears in parentheses next to the component or method name, or on the
parameter information line.
You use the hint attribute for longer descriptions of the component, method, or argument. In the introspection
display, this attribute appears on a separate line or on several lines of the component or method description, and at the
end of the argument description.
Metadata attributes
You can include arbitrary metadata information as attributes of the cfcomponent, cffunction, cfargument, and
cfproperty tags. To create a metadata attribute, specify the metadata attribute name and its value. For example, in
the following cfcomponent tag, the Author attribute is a metadata attribute. This attribute is not used as a function
parameter; instead, it indicates who wrote this CFC.
<cfcomponent name="makeForm" Author="Bean Lapin">
Metadata attributes are not used by ColdFusion for processing; they also do not appear in standard ColdFusion
introspection displays; however, you can access and display them by using the GetMetaData or
GetComponentMetaData function to get the metadata. Each attribute name is a key in the metadata structure of the
CFC element.
Metadata attributes are used for more than documentation. Your application can use the GetMetadata function to get
the metadata attributes for a component instance, or the GetComponentMetaData function to get the metadata for an
interface or component that you have not yet instantiated. You can then act based on the values. For example, a
mathCFC component could have the following cfcomponent tag:
<cfcomponent displayname="Math Functions" MetaType="Float">
In this case, a ColdFusion page with the following code sets the MetaTypeInfo variable to Float:
<cfobject component="mathCFC" name="MathFuncs">
<cfset MetaTypeInfo=GetMetadata(MathFuncs).MetaType>
Note: All metadata values are replaced by strings in the metadata structure returned from the GetMetadata function.
Because of this, do not use expressions in custom metadata attributes.
The cfproperty tag
The cfproperty tag is used to create complex data types with WSDL descriptors and for component property
documentation, as follows:
It can create complex data types with WSDL descriptions for ColdFusion web services. For more information, see
Using ColdFusion components to define data types for web services on page 1109.
It can provide documentation of component properties in the ColdFusion introspection output. The introspection
information includes the values of the standard cfproperty tag attributes.
Note: The cfproperty tag does not create a variable or assign it a value. It is used for information purposes only. You
use a cfset tag, or CFScript assignment statement, to create the property and set its value.
189
Form
Flash Remoting
Web services
ColdFusion page
Current directory
N/A
Yes
N/A
N/A
Yes
Web root
Yes
Yes
Yes
Yes
Yes
ColdFusion mappings
No
No
No
No
Yes
No
No
No
No
Yes
Note: ColdFusion mappings and custom tag roots can exist within the web root. If so, they are accessible to remote
requests, including URL, form, Flash Remoting, and web services invocation.
When you store components in the same directory, they are members of a component package. You can group related
CFCs into packages. Your application can refer to any component in a directory specifically by using a qualified
component name that starts with a subdirectory of one of the accessible directories and uses a period to delimit each
directory in the path to the directory that contains the component. For example, the following example is a qualified
name of a component named price:
catalog.product.price
In this example, the price.cfc file must be in the catalog\product subdirectory of a directory that ColdFusion searches
for components, as listed in the preceding table. When you refer to a component using the qualified name, ColdFusion
looks for the component in the order described in Specifying the CFC location on page 196.
Establishing a descriptive naming convention is a good practice, especially if you plan to install the components as part
of a packaged application.
can access the CFC methods and data as instance elements. You can also use the instance in the cfinvoke tag to
invoke the CFC methods. When you instantiate a CFC, data in the CFC is preserved as long as the CFC instance
exists, and ColdFusion does not incur the overhead of creating the instance each time you call a method.
Instantiate CFCs to preserve data in the CFC. To ensure processing efficiency if you use the CFC more than once
on a page, instantiate the CFC before you invoke its methods.
Methods that are executed remotely through Flash Remoting and web services always create an instance of the CFC
before executing the method.
2 You can invoke (call) a method of the CFC without creating an instance of the CFC, which is referred to as
transiently invoking a method. In this case, ColdFusion creates an instance of the CFC that exists only from the time
you invoke the method until the method returns a result. No data is preserved between invocations and ColdFusion
does not keep an instance of the CFC that you can reuse elsewhere in your CFML. It is considered a best practice
to create an instance of a CFC before invoking any of its methods, unless your CFML request uses the CFC only
once. If you transiently invoke a method frequently, consider creating a user-defined function to replace the CFC
method.
190
You can create persistent CFCs by assigning the CFC instance to a persistent scope, such as the Session or Application
scope. This way, you can create CFCs for objects, such as shopping carts or logged-in users, that must persist for
sessions. You can also create CFCs that provide application-specific data and methods.
Description
cfinvoke
cfinvokeargument
cfobject
CreateObject
Description
cfinvoke tag
Transiently invokes a component method using See Invoking component methods by using a form on
page 194.
the HTML form and input tags and their
attributes.
Flash Remoting
Web services
The cfinvoke tag and CFScript consume web See Using Web Services on page 1093.
services in ColdFusion. External applications can
also consume CFC methods as web services.
Instantiating CFCs
If you use a CFC multiple times in a ColdFusion request, or if you use a CFC with persistent properties, use the cfobject
tag or CreateObject function to instantiate the CFC before you call its methods.
The following example uses the cfobject tag to create an instance of the tellTime CFC.
<cfobject component="tellTime" name="tellTimeObj">
The following example uses the CreateObject function to instantiate the same component in CFScript:
tellTimeObj = CreateObject("component", "tellTime");
191
The CFC instance name, enclosed in number signs (#), in the component attribute.
The method name, in the method attribute.
Any parameters. For information on passing parameters, see Passing parameters to methods by using the cfinvoke
tag on page 196.
If the component method returns a result, the name of the variable for the result in the returnVariable attribute.
The following procedure creates an application that displays the current UTC and local time.
1 Create a file named tellTime2.cfc with the following code:
<cfcomponent>
<cffunction name="getLocalTime" access="remote">
<cfreturn TimeFormat(now())>
</cffunction>
<cffunction name="getUTCTime" access="remote">
<cfscript>
serverTime=now();
utcTime=GetTimeZoneInfo();
utcStruct=structNew();
utcStruct.Hour=DatePart("h", serverTime);
utcStruct.Minute=DatePart("n", serverTime);
utcStruct.Hour=utcStruct.Hour + utcTime.utcHourOffSet;
utcStruct.Minute=utcStruct.Minute + utcTime.utcMinuteOffSet;
if (utcStruct.Minute LT 10) utcStruct.Minute = "0" & utcStruct.Minute;
</cfscript>
<cfreturn utcStruct.Hour & ":" & utcStruct.Minute>
</cffunction>
</cfcomponent>
This example uses the cfobject tag to create an instance of the tellTime component and the cfinvoke tag to invoke the
instances getLocalTime and getUTCTime methods. In this example, the CFC contains the functional logic in the
methods, which return a result to the calling page, and the calling page displays the results. This structure separates the
logic from the display functions, which usually results in more reusable code.
192
If the component method returns a result, the name of the variable that contains the result, in the returnVariable
attribute.
The following procedure creates an application that displays the local time.
1 Create the following component and save it as tellTime.cfc:
<cfcomponent>
<cffunction name="getLocalTime">
<cfoutput>#TimeFormat(now())#</cfoutput>
</cffunction>
</cfcomponent>
The example defines a component with one method, getLocalTime, that displays the current time.
2 Create a ColdFusion page, with the following code, and save it in the same directory as the tellTime component:
<h3>Time Display Page</h3>
<b>Server's Local Time:</b>
<cfinvoke component="tellTime" method="getLocalTime">
Using the cfinvoke tag, the example invokes the getLocalTime component method without creating a persistent
CFC instance.
Using the cfinvoke tag within the CFC definition
You can use the cfinvoke tag to invoke a component method within the component definition; for example, to call a
utility method that provides a service to other methods in the component. To use the cfinvoke tag in this instance,
do not create an instance or specify the component name in the cfinvoke tag, as the following example shows:
<cfcomponent>
<cffunction name="servicemethod" access="public">
<cfoutput>At your service...<br></cfoutput>
</cffunction>
<cffunction name="mymethod" access="public">
<cfoutput>We're in mymethod.<br></cfoutput>
<!--- Invoke a method in this CFC. --->
<cfinvoke method="servicemethod">
</cffunction>
</cfcomponent>
Note: When you invoke a method from within the component definition in which you define the method, do not use the
This scope, because this resets the access privileges.
193
The cfinvoke tag then invokes the appropriate method, based on what the user selected:
<cfinvoke component="getdata" method="#form.whichreport#" returnvariable="queryall">
tellTimeObj instance.
3 The second WriteOutput function displays text followed by the results returned by the getUTCTime method of the
tellTimeObj instance.
In CFScript, you use the method name in standard function syntax, such as methodName().
Invoking component methods in CFML
The following example uses CFML tags to produce the same results as the CFScript example:
<cfobject name="tellTimeObj" component="tellTime">
<cfoutput>
Server's Local Time: #tellTimeObj.getLocalTime()#<br>
Calculated UTC Time: #tellTimeObj.getUTCTime()#
</cfoutput>
194
Note: To use URL invocation, set the access attribute of the cffunction tag to remote.
To pass parameters to component methods using a URL, append the parameters to the URL in standard URL querystring, name-value pair syntax; for example:
http://localhost:8500/corpQuery.cfc?method=getEmp&lastName=camden
To pass multiple parameters within a URL, use the ampersand character (&) to delimit the name-value pairs; for
example:
http://localhost:8500/corpQuerySecure.cfc?method=getAuth&store=women&dept=shoes
Note: To ensure data security, Adobe strongly recommends that you not pass sensitive information over the web using
URL strings. Potentially sensitive information includes all personal user information, including passwords, addresses,
telephone numbers, and so on.
If a CFC method that you access using the URL displays output directly, the users browser shows the output. You can
suppress output by specifying output="No" in the cffunction tag. If the CFC returns a result using the cfreturn tag,
ColdFusion converts the text to HTML edit format (with special characters replaced by their HTML escape sequences),
places the result in a WDDX packet, and includes the packet in the HTML that it returns to the client.
Invoking component methods by using a form
To invoke a method by using a ColdFusion or HTML form, do the following:
Specify the CFC filename or path in the form or cfform tag action attribute.
Specify the CFC method in a hidden form field, as follows:
<form action="myComponent.cfc" method="POST">.
<input type="Hidden" name="method" value="myMethod">
Alternatively, if you use the POST method to submit the form, you can follow the filename with
?method=methodname, where methodname is the name of the CFC method, as shown in the following line. You
Create an input tag for each component method parameter. The name attribute of the tag must be the method
parameter name and the field value is the parameter value.
Specify the access="remote" attribute in the cffunction tag that defines the CFC method being invoked
195
If the CFC method that you invoke from the form displays output directly, the users browser shows the output. (You
can use the cffunction tag output attribute to disable displaying output.) If the CFC returns a result using the cfreturn
tag, ColdFusion converts the text to HTML edit format, places it in a WDDX packet, and includes the packet in the
HTML that it returns to the client.
1 Create a corpFind.cfm file with the following contents:
<h2>Find People</h2>
<form action="components/corpQuery.cfc?method=getEmp" method="post">
<p>Enter employee's last Name:</p>
<input type="Text" name="lastName">
<input type="Hidden" name="method" value="getEmp">
<input type="Submit" title="Submit Query"><br>
</form>
In the example, the form tags action attribute points to the corpQuery component and invokes the getEmp
method.
2 Create a corpQuery.cfc file, specifying access="remote" for each cffunction tag, as the following example
shows:
<cfcomponent>
<cffunction name="getEmp" access="remote">
<cfargument name="lastName" required="true">
<cfset var empQuery="">
<cfquery name="empQuery" datasource="cfdocexamples">
SELECT LASTNAME, FIRSTNAME, EMAIL
FROM tblEmployees
WHERE LASTNAME LIKE '#arguments.lastName#'
</cfquery>
<cfoutput>Results filtered by #arguments.lastName#:</cfoutput><br>
<cfdump var=#empQuery#>
</cffunction>
</cfcomponent>
ColdFusion displays the search form. After you enter values and click the Submit Query button, the browser
displays the results.
For more information on using CFCs as web services, see Using Web Services on page 1093
196
If you use a cfinvoke or cfobject tag, or the CreateObject function, to access the CFC from a CFML page,
ColdFusion searches directories in the following order:
1 Local directory of the calling CFML page
2 Web root
3 Directories specified on the Custom Tag Paths page of ColdFusion Administrator
If you specify only a component name, ColdFusion searches each of these directories, in turn, for the component.
If you specify a qualified path, such as myApp.cfcs.myComponent, ColdFusion looks for a directory matching the
first element of the path in each of these directories (in this example, myApp). If ColdFusion finds a matching
directory, it looks for a file in the specified path beneath that directory, such as myApp\cfcs\myComponent.cfc,
relative to each of these directories.
Note: If ColdFusion finds a directory that matches the first path element, but does not find a CFC under that directory,
ColdFusion returns a not found error and does not search for another directory.
If you invoke a CFC method remotely, using a specific URL, a form field, Flash Remoting, or a web service
invocation, ColdFusion looks in the specified path relative to the web root. For form fields and URLs that are
specified directly on local web pages, ColdFusion also searches relative to the page directory.
Note: On UNIX and Linux systems, ColdFusion attempts to match a CFC name or custom tag name with a filename,
as follows: First, it attempts to find a file with the name that is all lowercase. If it fails, it tries to find a file whose case
matches the CFML case. For example, if you specify <cfobject name="myObject" Component="myComponent">,
ColdFusion first looks for mycomponent.cfc and, if it doesn't find it, ColdFusion looks for myComponent.cfc.
197
In the example, the parameters are passed as the lastName and pwd attributes.
Note: The cfinvoke tag attribute names are reserved and cannot be used for parameter names. The reserved attribute
names are: component, method, argumentCollection, and returnVariable. For more information, see the CFML
Reference.
Passing parameters in the argumentCollection attribute
If you save attributes to a structure, you can pass the structure directly using the cfinvoke tags argumentCollection
attribute. This technique is useful if an existing structure or scope (such as the Forms scope) contains values that you
want to pass to a CFC as parameters, and for using conditional or looping code to create parameters.
When you pass an argumentCollection structure, each structure key is the name of a parameter inside the structure.
The following example passes the Form scope to the addUser method of the UserDataCFC component. In the method,
each form field name is a parameter name; the method can use the contents of the form fields to add a user to a
database.
<cfinvoke component="UserDataCFC" method="addUser" argumentCollection="#Form#">
The cfinvokeargument tag passes the lastName parameter to the component method.
In the following example, a form already let the user select the report to generate. After instantiating the getdata and
reports components, the action page invokes the doquery component instance, which returns the query results in
queryall. The action page then invokes the doreport component instance and uses the cfinvokeargument tag to
pass the query results to the doreport instance, where the output is generated.
<cfobject component="getdata" name="doquery">
<cfobject component="reports" name="doreport">
<cfinvoke component="#doquery#" method="#form.whichreport#" returnvariable="queryall">
<cfinvoke component="#doreport#"method="#form.whichreport#">
<cfinvokeargument name="queryall" value="#queryall#">
</cfinvoke>
example:
authorized = securityCFC.getAuth(name="Almonzo", Password="LauRa123");
198
2 You can pass the parameters in an argumentCollection structure. The following code is equivalent to the
previous example:
argsColl = structNew();
argsColl.username = "Almonzo";
argsColl.password = "LauRa123";
authorized = securityCFC.getAuth(argumentCollection = argsColl);
3 You can pass positional parameters to a method by separating them with commas. The following example calls the
getAuth method, and passes the name and password as positional parameters:
authorized = securityCFC.getAuth("Almonzo", "LauRa123");
Note: For more information on using positional parameters and component methods in ColdFusion functions, see
Creating user-defined functions on page 153.
In the calling page, you can define and access CFC This scope variables by using the CFC instance name as the prefix.
For example, if you create a CFC instance named car and, within the car CFC specify <cfset
This.color="green">, a ColdFusion page that instantiates the CFC could refer to the components color property as
#car.color#.
Variable values in the This scope last as long as the CFC instance exists and, therefore, can persist between calls to
methods of a CFC instance.
Note: The This scope identifier works like the This keyword in JavaScript and ActionScript. CFCs do not follow the Java
class model, and the This keyword behaves differently in ColdFusion than in Java. In Java, This is a private scope, whereas
in ColdFusion, it is a public scope.
199
The CFC Variables scope does not include any of the Variables scope variables that are declared or available in the page
that instantiates or invokes the CFC. However, you can make the Variables scope of the page that invokes a CFC
accessible to the CFC by passing Variables as an argument to the CFC method.
You set a Variables scope variable by assigning a value to a name that has the Variables prefix or no prefix.
Values in the Variables scope last as long as the CFC instance exists, and therefore can last between calls to CFC
instance methods.
The Variables scope is available to included pages, and Variables scope variables that are declared in the included page
are available in the component page.
Note: The Variables scope is not the same as the function local scope, which makes variables private within a function.
Always define function-local variables using the var keyword of the Local scope name.
Example: sharing the Variables scope
The following example shows how to make the Variables scope of the page that invokes a CFC accessible to the CFC by
passing Variables as an argument to the CFC method. It also illustrates that the Variables scope is private to the CFC.
The following code is for the callGreetMe.cfm page:
<cfset Variables.MyName="Wilson">
<cfobject component="greetMe" name="myGreetings">
<cfoutput>
Before invoking the CFC, Variables.Myname is: #Variables.MyName#.<br>
Passing Variables scope to hello method. It returns:
#myGreetings.hello(Variables.MyName)#.<br>
After invoking the CFC, Variables.Myname is: #Variables.MyName#.<br>
</cfoutput>
<cfinvoke component="greetMe" method="VarScopeInCfc">
200
Any arguments declared with the cfargument tag must appear before any variables defined with the cfset tag. You
can also place any cfscript tag first and define variables that you declare with the Var keyword in the script.
Use function local variables if you place the CFC in a persistent scope such as the Session scope, and the function has
data that must be freed when the function exits.
Local variables do not persist between calls to CFC methods.
Local variables are available to pages included by the method.
201
derived from the base component. Typically a base component is more general, and subcomponents are typically more
specific. Each subclass does not have to redefine the code in the base component, but can override it if necessary.
The Super keyword Lets a component that overrides a base component method execute the original base component
method. This technique lets your subclassed component override a method without losing the ability to call the
original version of the method.
Using component inheritance
Component inheritance lets you import component methods and properties from one component to another
component. Inherited components share any component methods or properties that they inherit from other
components, and ColdFusion initializes instance data in the parent CFC when you instantiate the CFC that extends it.
Component inheritance defines an is a relationship between components. For example, a component named
president.cfc inherits its methods and properties from manager.cfc, which inherits its methods and properties from
employee.cfc. In other words, president.cfc is a manager.cfc; manager.cfc is an employee.cfc; and president.cfc is an
employee.cfc.
In this example, employee.cfc is the base component; its the component upon which the others are based. The
manager component extends the employee component; it has all the methods and properties of the employee
component, and some additional ones. The president component extends the manager component. The president
component is called a subcomponent or child component of the manager component, which, in turn, is a child
component of the employee component.
1 Create the employee.cfc file with the following content:
<cfcomponent>
<cfset This.basesalary=40*20>
</cfcomponent>
In the example, the cfcomponent tags extends attribute points to the employee component.
3 Create the president.cfc file with the following content:
<cfcomponent extends="manager">
<cfset This.prezBonus=40*20>
</cfcomponent>
In the example, the cfcomponent tags extends attribute points to the manager component.
202
4 Create the inherit.cfm file with the following content, and save it in the same directory as the components you
When you browse the inherit.cfm file, the manager component refers to the basesalary defined in employee.cfc,
which is the base component; the president component refers to both the basesalary defined in the employee
component, and the mgrBonus defined in the manager component. The manager component is the parent class of the
president component.
Using the component.cfc file
All CFCs automatically extend the ColdFusion WEB-INF/cftags/component.cfc component. (The WEB-INF
directory is in the cf_root/wwwroot directory on ColdFusion configured with an embedded J2EE server. It is in the
cf_root directory when you deploy ColdFusion on a J2EE server.) This CFC is distributed as a zero-length file. You can
use it for any core methods or properties that you want all CFCs in your ColdFusion application server instance to
inherit.
Note: When you install a newer version of ColdFusion, the installation procedure replaces the existing component.cfc file
with a new version. Therefore, before upgrading, save any code that you have added to the component.cfc file, and then
copy the code into the new component.cfc file.
Using the Super keyword
You use the Super keyword only on CFCs that use the Extends attribute to extend another CFC. Unlike ColdFusion
scopes, the Super keyword is not used for variables; it is only used for CFC methods, and it is not available on
ColdFusion pages that invoke CFCs.
The Super keyword lets you refer to versions of methods that are defined in the CFC that the current component
extends. For example, the employee, manager, and president CFCs each contain a getPaid method. The manager CFC
extends the employee CFC. Therefore, the manager CFC can use the original versions of the overridden getPaid
method, as defined in the employee CFC, by prefixing the method name with Super.
1 Create the employee.cfc file with the following content:
<cfcomponent>
<cffunction name="getPaid" returntype="numeric">
<cfset var salary=40*20>
<cfreturn salary>
</cffunction>
</cfcomponent>
203
4 Create the payday.cfm file with the following content, and save it in the same directory as the components that you
In this example, each getPaid method in a child component invoked the getPaid method of its parent component.
The childs getPaid method then used the salary returned by the parents getPaid method to calculate the
appropriate amount.
Included pages can use the Super keyword.
Note: The Super keyword supports only one level of inheritance. If you use multiple levels of inheritance, you can only use
the Super keyword to access the current components immediate parent. The example in this section illustrates handling
this limitation by invoking methods in a chain.
Using component packages
Components stored in the same directory are members of a component package. Component packages help prevent
naming conflicts, and facilitate easy component deployment; for example:
ColdFusion searches the current directory first for a CFC. If you place two components in a single directory as a package,
and one component refers to the other with only the component name, not a qualified path, ColdFusion always searches
the package directory first for the component. As a result, if you structure each applications components into a package,
your applications can use the same component names without sharing the component code.
If you use the access="package" attribute in a methods cffunction tag, access to the method is limited to
components in the same package. Components in other packages cannot use this method, even if they specify it
with a fully qualified component name. For more information on access security, see Using access security on
page 204.
getUTCTime.cfm file that you created in Placing executable code in a separate file on page 181 to the components
directory.
4 Create the timeDisplay.cfm file with the following content and save it in your web root directory:
204
You use dot syntax to navigate directory structures. Place the directory name before the component name.
5 Browse the timeDisplay.cfm file in your browser.
Code that manipulates persistent scope CFC properties must be locked, just as all other code that manipulates
persistent scope properties must be locked. Therefore, lock both of the following types of application code:
205
Type
Description
private
Available only to the component that declares the method and any components that extend the component in
which it is defined. This usage is like the Java protected keyword, not the Java private keyword.
package
Available only to the component that declares the method, components that extend the component, or any other
components in the package. A package consists of all components defined in a single directory. For more
information on packages, see Using component packages on page 203.
public
remote
Available to a locally or remotely executing ColdFusion page or component method, or to a local or remote client
through a URL, form submission, Flash Remoting, or as a web service.
In the example, the cffunction tag includes the roles attribute to specify the user roles allowed to access it. In this
example, only users in the role admin and manager can access the function. Notice that multiple roles are delimited by
a comma.
For information on ColdFusion security, including the cflogin tag and role-based security in ColdFusion, see
Securing Applications on page 339.
Using programmatic security
You can implement your own security within a method to protect resources. For example you can use the ColdFusion
function IsUserInAnyRole to determine if a user is in particular role, as the following example shows:
<cffunction name="foo">
<cfif IsUserInRole("admin")>
do stuff allowed for admin
<cfelseif IsUserInRole("user")>
do stuff allowed for user
<cfelse>
<cfoutput>unauthorized access</cfoutput>
<cfabort>
</cfif>
</cffunction>
206
cf_root/wwwroot/CFIDE/componentutils directory.
2 The cfcexplorer component prompts users for the ColdFusion RDS or Administrator password, if necessary.
3 The cfcexplorer component renders an HTML description and returns it to the browser.
The upper-left pane lists all CFC packages that ColdFusion can access, and has all components and refresh links.
The lower-left pane lists CFC component names. When the browser first appears, or when you click the all
components link in the upper pane, the lower pane lists all available components. If you click a package name in
the upper left pane, the lower pane lists only the components in the package.
The right pane initially lists the paths of all components. When you click a component name in the lower-left pane,
the right pane shows the ColdFusion introspection page, as described in Requesting a component page from the
browser on page 206.
Note: When RDS user names are enabled, the component browser accepts the root administrator user (admin) with either
the administrator or RDS single password.
Using the Dreamweaver Components panel
The Dreamweaver Components panel lists all available components, including their methods, method parameters,
and properties. The panels context menu includes options to create a component, edit the selected component, insert
code to invoke the component, or show detailed information on the component or component element. The Get
description option shows the ColdFusion introspection page, as described in Requesting a component page from the
browser on page 206. For more information on viewing and editing CFCs in Dreamweaver, see the Dreamweaver
online Help.
Using the GetMetaData function
The CFML GetMetaData function returns a structure that contains all the metadata of a CFC instance. This structure
contains substantially more data about the CFC than the cfdump tag shows, and includes the following information:
All attributes to the component tag, including any metadata-only attributes, plus the component path.
An array of structures that contains complete information on each method (function) in the component. This
information describes all attributes, including metadata-only function and parameter attributes.
Within each function structure, a Parameters element that contains an array of parameters specified by cfargument
tags. Information on each parameter includes any metadata-only attributes.
207
Information about any properties that are specified using the cfproperty tag.
For information on how to specify CFC metadata, including how to use component tags and how to specify metadataonly attributes, see Documenting CFCs on page 187.
208
209
When ColdFusion processes the page containing this tag, it could output the message:
December 5, 1987 is Ted Cantor's Birthday.
Please wish him well.
A custom tag can also have a body and end tag, for example:
<cf_happybirthdayMessge name="Ellen Smith" birthDate="June 8, 1993">
<p> Happy Birthday Ellen!</p>
<p> May you have many more!</p>
</cf_happybirthdayMessge>
For more information about using end tags, see Handling end tags on page 217.
This custom tag returns the current date in the format DD-MMM-YY.
As you can see from this example, creating a custom tag in CFML is no different from writing any ColdFusion page.
You can use all CFML constructs, as well as HTML. You are free to use any naming convention that fits your
development practice. Unique descriptive names make it easy for you and others to find the right tag.
Note: Although tag names in ColdFusion pages are not case sensitive, custom tag filenames must be lowercase on UNIX.
Storing custom tag pages
You must store custom tag pages in any one of the following:
210
Description
template
Required if the name attribute is not used. Same as the template attribute in cfinclude. This attribute:
If the path value is prefixed with "/", ColdFusion searches directories explicitly mapped in the ColdFusion
Administrator for the included file.
Example: <cfmodule template="../MyTag.cfm"> identifies a custom tag file in the parent directory.
name
Required if the template attribute is not used. Use period-separated names to uniquely identify a subdirectory
under the CustomTags root directory.
Example: <cfmodule name="MyApp.GetUserOptions"> identifies the file GetUserOptions.cfm in the
CustomTags\MyApp directory under the ColdFusion root directory.
attributes
For example, the following code specifies to execute the custom tag defined by the mytag.cfm page in the parent
directory of the calling page:
<cfmodule template="../mytag.cfm">
For more information on using the cfmessagebox tag, see the CFML Reference.
Calling custom tags with the cfimport tag
You can use the cfimport tag to import custom tags from a directory as a tag library. The following example imports
the tags from the directory myCustomTags:
<cfimport prefix="mytags" taglib="myCustomTags">
Once imported, you call the custom tags using the prefix that you set when importing, as the following example shows:
<mytags:customTagName>
where customTagName corresponds to a ColdFusion application page named customTagName.cfm. If the tag takes
attributes, you include them in the call:
<mytags:custom_tag_name attribute1=val_1 attribute2=val_2>
211
You can also include end tags when calling your custom tags, as the following example shows:
<mytags:custom_tag_name attribute1=val_1 attribute2=val_2>
...
</mytags:custom_tag_name>
ColdFusion calls the custom tag page twice for a tag that includes an end tag: once for the start tag and once for the
end tag. For more information on how ColdFusion handles end tags, and how to write your custom tags to handle
them, see Handling end tags on page 217.
One of the advantages to using the cfimport tag is that you can define a directory structure for your custom tags to
organize them by category. For example, you can place all security tags in one directory, and all interface tags in
another. You then import the tags from each directory and give them a different prefix:
<cfimport prefix="security" taglib="securityTags">
<cfimport prefix="ui" taglib="uiTags">
...
<security:validateUser name="Bob">
...
<ui:greeting name="Bob">
...
Reading your code becomes easier because you can identify the location of your custom tags from the prefix.
212
<cf_getmd Name=#NameYouEntered#>
To pass multiple attributes to a custom tag, separate them with a space in the tag as follows:
<cf_mytag Firstname="Thadeus" Lastname="Jones">
In the custom tag, you use the Attributes scope to access attributes passed to the tag. Therefore, in the getmd.cfm page,
you access the passed attribute as Attributes.Name. The mytag.cfm custom tag page refers to the passed attributes as
Attributes.Firstname and Attributes.Lastname.
The custom tag page can also access variables set in the calling page by prefixing the calling pages local variable with
Caller. However, this technique is not the best way to pass information to a custom tag, because each calling page
would be required to create variables with the names required by the custom tag. You can create more flexible custom
tags by passing parameters using attributes.
Variables created within a custom tag are deleted when the processing of the tag terminates. Therefore, if you want to
pass information back to the calling page, write that information back to the Caller scope of the calling page. You
cannot access the custom tags variables outside the custom tag itself.
For example, use the following code in the getmd.cfm page to set the variable Doctor on the calling page:
<cfset Caller.Doctor="Doctor " & Attributes.Name>
If the variable Doctor does not exist in the calling page, this statement creates it. If the variable exists, the custom tag
overwrites it.
The following image shows the relationship between the variables on the calling page and the custom tag:
<cfset NameYouEntered="Smith">
<cf_getmd Name=#NameYouEntered#>
<cfoutput>
You are now #Variables.Doctor#.<br>
</cfoutput>
A. calling page B. getmd.cfm
One common technique used by custom tags is for the custom tag to take as input an attribute that contains the name
of the variable to use to pass back results. For example, the calling page passes returnHere as the name of the variable
to use to pass back results:
<cf_mytag resultName="returnHere">
In mytag.cfm, the custom tag passes back its results using the following code:
<cfset "Caller.#Attributes.resultName#" = result>
Be careful not to overwrite variables in the calling page from the custom tag. Adopt a naming convention to minimize
the chance of overwriting variables. For example, prefix the returned variable with customtagname_, where
customtagname is the name of the custom tag.
Note: Data that pertains to the HTTP request or to the current application is visible in the custom tag page. This data
includes the variables in the Form, URL, Cgi, Request, Cookies, Server, Application, Session, and Client scopes.
213
Use the cfparam tag or a cfif tag with an IsDefined function at the top of a custom tag to test for required
attributes that must be passed from a calling page; for example, the following code issues an abort if the user does
not specify the Name attribute to the custom tag:
<cfif not IsDefined("Attributes.Name")>
<cfabort showError="The Name attribute is required.">
</cfif>
214
<html>
<head>
<title>Enter Name</title>
</head>
<body>
<!--- Enter a name, which could also be done in a form. --->
<!--- This example simply uses a cfset. --->
<cfset NameYouEntered="Smith">
<!--- Display the current name. --->
<cfoutput>
Before you leave this page, you're #Variables.NameYouEntered#.<br>
</cfoutput>
<!--- Go to the custom tag. --->
<cf_getmd Name="#NameYouEntered#">
<!--- Come back from the Custom tag --->
<!--- Display the results of the custom tag. --->
<cfoutput>
You are now #Variables.Doctor#.<br>
</cfoutput>
</body>
</html>
The calling page uses the getmd custom tag and displays the results.
Reviewing the code
The following table describes the code and its function:
215
Code
Description
<cfset NameYouEntered="Smith">
<cfoutput>
Before you leave this page, you're
#Variables.NameYouEntered#.<br>
</cfoutput>
<cf_getmd Name="#NameYouEntered#">
In the calling page, call the getmd custom tag and pass it the Name
attribute whose value is the value of the local variable
NameYouEntered.
The custom tag page normally gets the Name variable in the
Attributes scope from the calling page. Assign it the value Who if
the calling page did not pass an attribute.
<cfoutput>
You are now #Variables.Doctor#.<br>
</cfoutput>
216
One use for attributeCollection is to pass the entire Attributes scope of one custom tag to another. This technique
is useful when you have one custom tag that calls a second custom tag and you want to pass all attributes from the first
tag to the second.
For example, you call a custom tag with the following code:
<cf_first attr1="foo" attr2="bar">
To pass all the attributes of the first custom tag to the second, you include the following statement in first.cfm:
<cf_second attributeCollection="#attributes#">
Within the body of second.cfm, you reference the parameters passed to it as follows:
<cfoutput>#attributes.attr1#</cfoutput>
<cfoutput>#attributes.attr2#</cfoutput>
217
Variable
Description
ExecutionMode
Contains the execution mode of the custom tag. Valid values are "start", "end", and "inactive".
HasEndTag
Distinguishes between custom tags that are called with and without end tags. Used for code validation. If the
user specifies an end tag, HasEndTag is set to true; otherwise, it is set to false.
GeneratedContent
Specifies the content that the tag generates. This content includes anything in the body of the tag, including
the results of any active content, such as ColdFusion variables and functions. You can process this content as
a variable.
AssocAttribs
Contains the attributes of all nested tags if you use cfassociate to make them available to the parent tags.
For more information, see High-level data exchange on page 221.
The following example accesses the ExecutionMode variable of the thisTag structure from within a custom tag:
<cfif thisTag.ExecutionMode is 'start'>
In this case, ColdFusion calls the custom tag page date.cfm to process the tag.
However, you can create custom tags that have both a start and an end tag. For example, the following tag has both a
start and an end tag:
<cf_date>
...
</cf_date>
ColdFusion calls the custom tag page date.cfm twice for a tag that includes an end tag: once for the start tag and once
for the end tag. As part of the date.cfm page, you can determine if the call is for the start or end tag, and perform the
appropriate processing.
ColdFusion also calls the custom tag page twice if you use the shorthand form of an end tag:
<cf_date/>
You can also call a custom tag using the cfmodule tag, as shown in the following example:
<cfmodule ...>
...
</cfmodule>
If you specify an end tag to cfmessagebox, then ColdFusion calls your custom tag as if it had both a start and an end tag.
Determining if an end tag is specified
You can write a custom tag that requires users to include an end tag. If a tag must have an end tag provided, you can
use thisTag.HasEndTag in the custom tag page to verify that the user included the end tag.
For example, in date.cfm, you could include the following code to determine whether the end tag is specified:
<cfif thisTag.HasEndTag is 'False'>
<!--- Abort the tag--->
<cfabort showError="An end tag is required.">
</cfif>
218
If an end tag is not explicitly provided, ColdFusion invokes the custom tag page only once, in Start mode.
A custom tag page named bold.cfm that makes text bold could be written as follows:
<cfif thisTag.ExecutionMode is 'start'>
<!--- Start tag processing --->
<B>
<cfelse>
<!--- End tag processing --->
</B>
</cfif>
You can also use cfswitch to determine the execution mode of a custom tag:
<cfswitch expression=#thisTag.ExecutionMode#>
<cfcase value= 'start'>
<!--- Start tag processing --->
</cfcase>
<cfcase value='end'>
<!--- End tag processing --->
</cfcase>
</cfswitch>
Use the start tag to validate input attributes, set default values, and validate the presence of the end tag if the custom
tag requires it.
Use the end tag to perform the actual processing of the tag, including any body text passed to the tag between the
start and end tags. For more information on body text, see Processing body text on page 218.
Perform output in either the start or end tag; do not divide it between the two tags.
In this example, the two lines of code after the start tag are the body text.
219
You can access the body text within the custom tag using the thisTag.GeneratedContent variable. The variable
contains all body text passed to the tag. You can modify this text during processing of the tag. The contents of the
thisTag.GeneratedContent variables are returned to the browser as part of the tags output.
The thisTag.GeneratedContent variable is always empty during the processing of a start tag. Any output generated
during start tag processing is not considered part of the tags generated content.
A custom tag can access and modify the generated content of any of its instances using the
thisTag.GeneratedContent variable. In this context, the term generated content means the results of processing the
body of a custom tag. The content includes all text and HTML code in the body, the results of evaluating ColdFusion
variables, expressions, and functions, and the results generated by descendant tags. Any changes to the value of this
variable result in changes to the generated content.
As an example, consider a tag that comments out the HTML generated by its descendants. Its implementation could
look as follows:
<cfif thisTag.ExecutionMode is 'end'>
<cfset thisTag.GeneratedContent ='<!--#thisTag.GeneratedContent#-->'>
</cfif>
Behavior
ExitTag (default)
Base page
ExecutionMode=start
ExecutionMode=end
Base page
ExecutionMode=start
ExecutionMode=end
Base page
Error
ExecutionMode=start
Error
ExecutionMode=end
ExitTemplate
Loop
220
The following example shows a cftreeitem tag nested within a cftree tag:
<cftree name="tree1"
required="Yes"
hscroll="No">
<cftreeitem value=fullname
query="engquery"
queryasroot="Yes"
img="folder,document">
</cftree>
The calling tag is known as an ancestor, parent, or base tag; the tags that ancestor tags call are known as descendant,
child, or sub tags. Together, the ancestor and all descendant tags are called collaborating tags.
In order to nest tags, the parent tag must have a closing tag.
The following table lists the terms that describe the relationships between nested tags:
Calling tag
Description
Ancestor
Descendant
An ancestor is any tag that contains other tags between its start and end tags.
A descendant is any tag called by a tag.
Parent
Child
Base tag
Sub tag
You can create multiple levels of nested tags. In this case, the sub tag becomes the base tag for its own sub tags. Any
tag with an end tag present can be an ancestor to another tag.
Nested custom tags operate through three modes of processing, which are exposed to the base tags through the variable
thisTag.ExecutionMode.
221
To preserve encapsulation, place all tag data access and modification operations in custom tags. For example, rather
than documenting that the variable MyQueryResults in a tag's implementation holds a query result and expecting
users to manipulate MyQueryResults directly, create a nested custom tag that manipulates MyQueryResult. This
technique protects the users of the custom tag from changes in the tag's implementation.
The baseTag attribute specifies the name of the base tag that gets access to this tags attributes. The dataCollection
attribute specifies the name of the structure in which the base tag stores the subtag data. Its default value is
AssocAttribs. ColdFusion requires a dataCollection attribute only if the base tag can have more than one type of
subtag. It is convenient for keeping separate collections of attributes, one per tag type.
Note: If the custom tag requires an end tag, the code processing the structure referenced by the dataCollection attribute
must be part of end-tag code.
When cfassociate is encountered in a sub tag, the sub tags attributes are automatically saved in the base tag. The
attributes are in a structure appended to the end of an array whose name is thisTag.collectionName.
The cfassociate tag performs the following operations:
222
The code accessing subtag attributes in the base tag could look like the following:
<!--- Protect against no subtags --->
<cfparam Name='thisTag.assocAttribs' default=#arrayNew(1)#>
<!--- Loop over the attribute sets of all sub tags --->
<cfloop index=i from=1 to=#arrayLen(thisTag.assocAttribs)#>
<!--- Get the attributes structure --->
<cfset subAttribs = thisTag.assocAttribs[i]>
<!--- Perform other operations --->
</cfloop>
GetBaseTagList: Returns a comma-delimited list of uppercase ancestor tag names, as a string. The first list
element is the current tag, the next element is the parent tag name if the current tag is a nested tag. If the function
is called for a top-level tag, it returns an empty string.
GetBaseTagData, InstanceNumber=1): Returns an object that contains all the variables (not just the local
variables) of the nth ancestor with a given name. By default, the closest ancestor is returned. If there is no ancestor
by the given name, or if the ancestor does not expose any data (such as cfif), an exception is thrown.
223
224
<cfoutput>
I'm running in the context of a custom tag named #inCustomTag#.<p>
</cfoutput>
<!--- Get the tag instance data. --->
<cfset tagdata = getbasetagdata(incustomtag)>
<!--- Find out the tag's execution mode. --->
I'm located inside the
<cfif tagdata.thisTag.executionmode neq 'inactive'>
custom tag code either because it is in its start or end execution mode.
<cfelse>
body of the tag
</cfif>
<p>
<cfelse>
<!--- Say that you are lonely. --->
I'm not nested inside any custom tags. :^( <p>
</cfif>
</cfif>
225
Action
Demonstrates
HelloColdFusion
ZipBrowser
ServerDateTime
OutputQuery
HelloWorldGraphic
Consult your Java development tool documentation to determine how to configure the compiler classpath for your
particular environment.
The cfx.jar archive contains the classes in the com.allaire.cfx package, which are required for developing and
deploying Java CFX tags.
When you create new Java CFX tags, compile them into the WEB-INF/classes directory. Doing so simplifies your
development, debugging, and testing processes.
226
After you finish with development and testing, you can deploy your Java CFX tag anywhere on the classpath visible to
ColdFusion.
bundled with the JDK, use the following command line, which you execute from within the classes directory:
javac -classpath cf_root\WEB-INF\lib\cfx.jar MyHelloColdFusion.java
Note: The previous command works only if the Java compiler (javac.exe) is in your path. If it is not in your path, specify
the fully qualified path; for example, c:\jdk1.3.1_01\bin\javac in Windows or /usr/java/bin/javac in UNIX.
If you receive errors during compilation, check the source code to make sure that you entered it correctly. If no errors
occur, you successfully wrote your first Java CFX tag.
227
2 Save the file in a directory configured to serve ColdFusion pages. For example, you can save the file as
on page 234).
4 Request the page from your browser using the appropriate URL; for example:
http://localhost/cfdocs/testjavacfx.cfm
ColdFusion processes the page and returns a page that displays the text Hello, Les. If an error is returned instead,
check the source code to make sure that you entered it correctly.
Delete a CFX tag in the ColdFusion Administrator
1 In the ColdFusion Administrator, select Extensions > CFX Tags.
2 For the tag to delete, click the Delete icon in the Controls column of the Registered CFX Tags list.
Processing requests
Implementing a Java CFX tag requires interaction with the Request and Response objects passed to the
processRequest method. In addition, CFX tags that must work with ColdFusion queries also interface with the
Query object. The com.allaire.cfx package, located in the WEB-INF/lib/cfx.jar archive, contains the Request,
Response, and Query objects.
For a complete description of these object types, see ColdFusion Java CFX Reference in the CFML Reference. For a
complete example Java CFX tag that uses Request, Response, and Query objects, see ZipBrowser example on
page 228.
Request object
The Request object is passed to the processRequest method of the CustomTag interface. The following table lists the
methods of the Request object for retrieving attributes, including queries, passed to the tag and for reading global tag
settings:
Method
Description
attributeExists
debug
getAttribute
getAttributeList
228
Method
Description
getIntAttribute
getQuery
getSetting
For detailed reference information on each of these interfaces, see the CFML Reference.
Response object
The Response object is passed to the processRequest method of the CustomTag interface. The following table lists the
methods of the Response object for writing output, generating queries, and setting variables within the calling page:
Method
Description
write
setVariable
addQuery
writeDebug
For detailed reference information on each of these interfaces, see the CFML Reference.
Query object
The Query object provides an interface for working with ColdFusion queries. The following table lists the methods of
the Query object for retrieving name, row count, and column names and methods for getting and setting data
elements:
Method
Description
getName
getRowCount
getColumnIndex
getColumns
getData
addRow
setData
For detailed reference information on each of these interfaces, see CFML Reference.
229
ZipBrowser example
The following example shows the use of the Request, Response, and Query objects. The example uses the java.util.zip
package to implement a Java CFX tag called cfx_ZipBrowser, which is a ZIP file browsing tag.
Note: The Java source file that implements cfx_ZipBrowser, ZipBrowser.java, is included in the
cf_root/cfx/java/distrib/examples (server configuration) or cf_webapp_root/WEBINF/cfusion/cfx/java/distrib/examples (J2EE configuration) directory. Compile ZipBrowser.java to implement the tag.
The tag archive attribute specifies the fully qualified path of the ZIP archive to browse. The tag name attribute must
specify the query to return to the calling page. The returned query contains three columns: Name, Size, and
Compressed.
For example, to query an archive at the path C:\logfiles.zip for its contents and output the results, you use the following
CFML code:
<cfx_ZipBrowser
archive="C:\logfiles.zip"
name="LogFiles">
<cfoutput query="LogFiles">
#Name#,#Size#, #Compressed# <BR>
</cfoutput>
com.allaire.cfx.* ;
java.util.Hashtable ;
java.io.FileInputStream ;
java.util.zip.* ;
230
Debug the CFX tag while it is running within ColdFusion by outputting the debug information as needed.
Debug the CFX tag using a Java IDE (Integrated Development Environment) that supports debugging features,
such as setting breakpoints, stepping through your code, and displaying variable values.
Debug the request in an interactive debugger offline from ColdFusion using the special com.allaire.cfx debugging
classes.
To determine whether a CFX tag is run with the debug attribute, use the Request.debug method. To write debugging
output in a special debugging block after the tag finishes executing, use the Response.writeDebug method. For
information on using these methods, see ColdFusion Java CFX Reference in CFML Reference.
231
configuration) and cf_root/runtime/lib/jrun.jar (server configuration only) are included in your classpath.
4 In your project settings, set your main class to jrunx.kernel.JRun and application parameters to -startdefault.
5 Debug your application by setting breakpoints, single stepping, displaying variables, or by performing other
debugging actions.
DebugRequest: An implementation of the Request interface that lets you initialize the request with custom
DebugResponse: An implementation of the Response interface that lets you print the results of a request once it
has completed.
DebugQuery: An implementation of the Query interface that lets you initialize a query with a name, columns, and
a data set.
Implement a main method
1 Create a main method for your Java CFX class.
2 Within the main method, initialize a DebugRequest and DebugResponse, and a DebugQuery. Use the appropriate
4 Call the DebugResponse.printResults method to output the results of the request, including content generated,
232
import java.util.Hashtable ;
import com.allaire.cfx.* ;
public class OutputQuery implements CustomTag {
// debugger testbed for OutputQuery
public static void main(String[] argv) {
try {
// initialize attributes
Hashtable attributes = new Hashtable() ;
attributes.put( "HEADER", "Yes" ) ;
attributes.put( "BORDER", "3" ) ;
// initialize query
String[] columns = { "FIRSTNAME", "LASTNAME", "TITLE" } ;
String[][] data = {
{ "Stephen", "Cheng", "Vice President" },
{ "Joe", "Berrey", "Intern" },
{ "Adam", "Lipinski", "Director" },
{ "Lynne", "Teague", "Developer" } };
DebugQuery query = new DebugQuery( "Employees", columns, data ) ;
// create tag, process debugging request, and print results
OutputQuery tag = new OutputQuery() ;
DebugRequest request = new DebugRequest( attributes, query ) ;
DebugResponse response = new DebugResponse() ;
tag.processRequest( request, response ) ;
response.printResults() ;
}
catch( Throwable e ) {
e.printStackTrace() ;
}
}
public void processRequest(Request request, Response response) throws Exception {
// ...code for processing the request...
}
}
CFX_NTUSERDB (Windows only): Lets you add and delete Windows NT users.
In Windows, these tags are located in the cf_root\cfx\examples directory. In UNIX, these tags are in the
cf_root/coldfusion/cfx/examples directory.
233
Compiler
Solaris
Sun Workshop C++ compiler, version 5.0 or higher (gcc cannot be used to compile CFX code on Solaris)
Linux
Before you can use your C++ compiler to build custom tags, enable the compiler to locate the CFX API header file,
cfx.h. In Windows, add the CFX API include directory to your list of global include paths. In Windows, this directory
is cf_root\cfx\include. In UNIX, this directory is cf_root/cfx/include. in UNIX, you need -I <includepath> on your
compile line (see the Makefile for the directory list example in the cfx/examples directory).
Adobe recommends that you shut down all other Java programs.
6 Execute any ColdFusion page that calls the CFX tag.
7 Select File > Open to open a file in VisualDev in which to set a breakpoint.
8 Set a breakpoint in the CFX project.
The best place is to place it in ProcessRequest(). Next time you execute the page you will reach the breakpoint.
234
For improved performance, when the tag is ready for production use, you can select this option to keep the DLL in
memory.
7 (Optional) Enter a description.
8 Click Submit.
235
About applications
The term application can mean many things. An application can be as simple as a guest book or as sophisticated as a
full Internet commerce system with catalog pages, shopping carts, and reporting.
An application, however, has a specific meaning in ColdFusion. A ColdFusion application has the following
characteristics:
It consists of one or more ColdFusion pages that work together and share a common set of resources.
All pages in the application share an application name and configuration settings as specified in an Application.cfc
file or a cfapplication tag.
Application pages share a common general purpose. For example, a web storefront is typically a single ColdFusion
application.
Many, but not necessarily all, pages in a ColdFusion application share data or common code elements, such as a
single login mechanism.
Application pages share a common look-and-feel, often enforced by using common code elements, such as the
same header and footer pages, and a common error message template.
236
Shared variables
The following ColdFusion variable scopes maintain data that lasts beyond the scope of the current HTTP request:
Variable scope
Variables available
Server
237
Variable scope
Variables available
Application
Client
For a single client browser over multiple browser sessions in one application
Session
For a single client browser for a single browser session in one application
For more information on using these variables, including how to use locks to ensure that the data they contain remains
accurate, see Using Persistent Data and Locking on page 301.
Trigger
Application start
ColdFusion starts processing the first request for a page in an application that is not running.
Application end
Session start
Session end
Request start
ColdFusion receives a request, including HTTP requests, messages to the event gateway, SOAP requests, or Flash
Remoting requests.
Request
Immediately after ColdFusion finishes processing the request start event. The handler for this event is intended
for use as a filter for the request contents. For more information on the differences between request start and
request events, see Managing requests in Application.cfc on page 246.
Request end
ColdFusion finishes processing all pages and CFCs for the request.
Exceptions
The Application.cfc file also defines application-wide settings, including the application name and whether the
application supports Session variables.
For more information on using application events and the Application.cfc file, see Defining the application and its
event handlers in Application.cfc on page 241.
238
The Application.cfm page can define the application. It can contain the cfapplication tag that specifies the
application name, and code on this page is processed for all pages in the application. This page can define applicationlevel settings, functions, and features.
The OnRequestEnd.cfm page is used in fewer applications than the Application.cfm page. It lets you provide common
clean-up code that gets processed after all application pages, or specify dynamic footer pages.
The OnRequestEnd.cfm page does not execute if the page runs a cflocation tag.
For more information on the Application.cfm and OnRequestEnd.cfm pages, see Using an Application.cfm page on
page 252. For information on placing these pages in the application directory structure, see Structuring an
application on page 239.
Note: You can create a ColdFusion application without using an Application.cfc, Application.cfm, or OnRequestEnd.cfm
page. However, it is much easier to use the Application.cfm page than to have each page in the application use a
cfapplication tag and define common application elements.
Mappings
Custom tag paths
These settings override the server-side settings in the ColdFusion Administrator for the specified application only.
Specifying per application settings does not change the server-wide settings. To set per-application settings, first enable
per-application settings on the Settings page of the ColdFusion Administrator. You then set the mappings or custom
tag paths in the Application.cfc file.
Custom Tags in per-application settings override those defined in the ColdFusion Administrator. For example, if you
have two custom tags of the same name and they are in different locations in the Administrator and per-application
settings, the one in the per-application settings is taken first.
Note: Per-application settings are supported in applications that use an Application.cfc file only, not in applications that
use an Application.cfm file. The per-application settings do not work if you have disabled application variables in the
Memory Variables page of the Administrator.
Set the mappings per application
1 Check the Enable Per App Settings option on the Settings page of the ColdFusion Administrator.
2 Include code like the following in your Application.cfc file:
<cfset THIS.mappings["/MyMap"]="c:\inetpub\myStuff">
or
<cfset StructInsert(THIS.mappings, "/MyMap", "c:\inetpub\myStuff")>
(To use the second format, you must first create a THIS.mappings structure.)
Set the custom tag paths per application
1 Check the Enable Per App Settings option on the Settings page of the ColdFusion Administrator.
2 Include code like the following in your Application.cfc file:
<cfset customtagpaths = "c:\mapped1,c:\mapped2">
<cfset customtagpaths = ListAppend(customtagpaths,"c:\mapped3")>
<cfset This.customtagpaths = customtagpaths>
239
mechanism to ensure that users only access and use selected features of the application. User security also incorporates
a user ID, which you use to customize page content. To implement user security, you include security code, such as
the cflogin and cfloginuser tags, in your application.
For more on implementing security, see Securing Applications on page 339.
Structuring an application
When you design a ColdFusion application, structure its contents into directories and files, also known as mapping
the directory structure. This activity is an important step in designing a ColdFusion application. Before you start
building the application, establish a root directory for the application. You store application pages in subdirectories of
the root directory.
It searches the pages directory for a file named Application.cfc. If one exists, it creates a new instance of the CFC,
processes the initial events, and stops searching. (ColdFusion creates a new instance of the CFC and processes
its initialization code for each request.)
If the requested pages directory does not have an Application.cfc file, it checks the directory for an
Application.cfm file. If one exists, ColdFusion logically includes the Application.cfm page at the beginning of
the requested page and stops searching further.
If the requested pages directory does not have an Application.cfc or Application.cfm file, ColdFusion searches
up the directory tree and checks each directory first for an Application.cfc file and then, if one is not found, for
an Application.cfm page, until it reaches the root directory (such as C:\). When it finds an Application.cfc or
Application.cfm file, it processes the page and stops searching.
2 ColdFusion processes the requested pages contents.
3 When the request ends, ColdFusion does the following:
If you have an Application.cfc, ColdFusion processes the CFCs onRequestEnd method and releases the CFC
instance.
240
If you do not have an Application.cfc, but do have an Application.cfm page, ColdFusion looks for an
OnRequestEnd.cfm in the same directory as the Application.cfm page ColdFusion uses for the current page.
ColdFusion does not search beyond that directory, so it does not run an OnRequestEnd.cfm page that resides
in another directory. Also, the OnRequestEnd.cfm page does not run if there is an error or an exception on the
application page, or if the application page executes the cfabort or cfexit tag.
The following rules determine how ColdFusion processes application pages and settings:
ColdFusion processes only one Application.cfc or Application.cfm page for each request. If a ColdFusion page has
a cfinclude tag pointing to an additional ColdFusion page, ColdFusion does not search for an Application.cfc or
Application.cfm page when it includes the additional page.
If a ColdFusion page has a cfapplication tag, it first processes any Application.cfc or Application.cfm, and then
processes the cfapplication tag. The tag overrides the settings from the application files, including the
application name and the behaviors set by the cfapplication tag attributes.
You can have multiple Application.cfc files, Application.cfm files, and cfapplication tags that use the same
application name. In this case, all pages that have the same name share the same application settings and
Application scope and set and get all the variables in this scope. ColdFusion uses the parameter settings of the
cfapplication tag or the most recently processed file, if the settings, such as the session time-out, differ among
the files.
Note: If your application runs on a UNIX platform, which is case-sensitive, spell Application.cfc, Application.cfm, and
OnRequestEnd.cfm with capital letters.
functions.
Security Application pages that are under the same directory can share web server security settings.
When you place your application in an application-specific directory hierarchy, you can use a single application
definition (Application.cfc or Application.cfm) page in the application root directory, or place different application
definition pages that govern individual sections of the application in different directories.
You divide your logical web application into multiple ColdFusion applications by using multiple application definition
pages with different application names. Alternatively, use multiple application definition pages that specify the same
application name, but have different code, for different subsections of your application.
The directory trees in the following image show two approaches to implementing an application framework:
In the example on the left, a company named Web Wonders, Inc. uses a single Application.cfc file installed in the
application root directory to process all application page requests.
241
In the example on the right, Bandwidth Associates uses the settings in individual Application.cfc files to create
individual ColdFusion applications at the departmental level. Only the Products application pages are processed
using the settings in the root Application.cfc file. The Consulting, Marketing, and Sales directories each have their
own Application.cfc file.
Bandwidth Associates
Application.cfc
Application.cfc
Products
Products
Orders
Consulting
Application.cfc
Support
Services
Marketing
Application.cfc
Sales
Application.cfc
Application-wide settings and variables include page processing settings, default variables, data sources, style
settings, and other application-level constants.
Application event handlers are CFC methods that ColdFusion automatically executes when specific events occur
during the lifetime of an application: application start and end, session start and end, request start, execution, and
end, and exceptions.
Application name
Application properties, including Client-, Application-, and Session-variable management options
Page processing options
Default variables, data sources, style settings, and other application-level constants
For information on setting default variables, see Setting application default variables and constants in
onApplicationStart on page 245.
242
Default
Description
applicationTimeout
Administrator value
Life span, as a real number of days, of the application, including all Application
scope variables. Use the createTimeSpan function to generate this variable.
clientManagement
False
clientStorage
Administrator value
Where Client variables are stored; can be cookie, registry, or the name of a
data source.
loginStorage
Cookie
Whether to store login information in the Cookie scope or the Session scope.
scriptProtect
Administrator Value
sessionManagement
False
sessionTimeout
Administrator Value
Life span, as a real number of days, of the user session, including all Session
variables. Use the createTimeSpan function to generate this variable.
setClientCookies
True
setDomainCookies
False
Whether to use domain cookies for the CFID and CFTOKEN values used for
client identification, and for Client scope variables stored using cookies. If
False, ColdFusion uses host-specific cookies. Set to True for applications
running on clusters.
The following example code from the top of an Application.cfc sets the application name and properties:
<cfcomponent>
<cfset This.name = "TestApplication">
<cfset This.clientmanagement="True">
<cfset This.loginstorage="Session">
<cfset This.sessionmanagement="True">
<cfset This.sessiontimeout="#createtimespan(0,0,10,0)#">
<cfset This.applicationtimeout="#createtimespan(5,0,0,0)#">
For more information on these settings, see cfapplication in the CFML Reference.
Setting page processing options
The cfsetting tag lets you specify the following page processing attributes to apply to all pages in your application:
243
Attribute
Use
showDebugOutput
Specifies whether to show debugging output. This setting cannot enable debugging if it is disabled
in the ColdFusion Administrator. However, this option ensures that debugging output is not
displayed, even if the Administrator enables it.
requestTimeout
Specifies the page request time-out. If ColdFusion cannot complete processing a page within the
time-out period, it generates an error. This setting overrides the setting in the ColdFusion
Administrator. Use this setting to increase the page time-out if your application or page frequently
accesses external resources that are slow, such as external LDAP servers or web services providers.
enableCFOutputOnly
Disables output of text that is not included inside cfoutput tags. This setting helps ensure that
extraneous text in your ColdFusion pages does not get displayed.
Often, you use the cfsetting tag on individual pages, but you can also use it in your Application.cfc file. For example,
using it in multi-application environment to override the ColdFusion Administrator settings in one application.
You can place an application-wide cfsetting tag in the component initialization code, normally following the This
scope application property settings, as the following example shows:
<cfcomponent>
<cfscript>
This.name="MyAppl";
This.clientmanagement="True";
This.loginstorage="Session" ;
This.sessionmanagement="True" ;
This.sessiontimeout=CreateTimeSpan(0,0,1,0);
</cfscript>
<cfsetting showdebugoutput="No" enablecfoutputonly="No">
The cfsetting tag in this example affects all pages in an application. You can override the application-wide settings
in the event methods, such as onRequestStart, or on individual ColdFusion pages.
When run
onApplicationStart
The application first starts: when the first request for a page is processed or the first CFC method is
invoked by an event gateway instance, Flash Remoting request, or a web service invocation.
This method is useful for setting application-wide (Application scope) variables, such as the names
of data sources.
onApplicationEnd
The application ends: when the application times out or the server shuts down.
onSessionStart
A new session is created as a result of a request that is not in an existing session, including
ColdFusion event gateway sessions. The application must enable sessions for this event to happen.
onSessionEnd
A session time-out setting is reached. This event is not triggered when the application ends or the
server shuts down.
onRequestStart
ColdFusion receives any of the following: a request, an HTTP request (for example, from a browser),
a message to an event gateway, a SOAP request, or a Flash Remoting request.
onRequest
The onRequestStart event has completed. This method acts as a filter for the requested page
content.
244
Method
When run
onRequestEnd
All pages and CFCs in the request have been processed: equivalent to the OnRequestEnd.cfm page.
onMissingTemplate
onError
When ColdFusion receives a request, it instantiates the Application CFC and runs the Application.cfc code in the
following order:
onRequestStart
onRequestEnd
onApplicationEnd
onSessionEnd
onMissingTemplate
onError
The onApplicationEnd and onSessionEnd methods do not execute in the context of a page request, so they cannot
access request variables or display information to the user. The onMissingTemplate method is triggered when a URL
specifies a CFML page that does not exist. The OnError method does not always execute in the context of a request;
use its Event argument to determine the context.
245
If your application requires utility functions that are used by multiple pages, not just by the methods in Application.cfc,
and you do not use an onRequest method, Adobe recommends that you place them in a separate CFC and access them
by running that CFC. As with other ColdFusion pages, Application.cfc can access any CFC in a directory path that is
configured on the ColdFusion Administrator Mappings page. Therefore, use this technique to share utility functions
across applications.
If your Application.cfc defines utility functions that you want available on request pages and does not use an
onRequest method, explicitly place the functions in a ColdFusion scope, such as the Request scope, as the following
code shows:
<cffunction name="theFunctionName" returntype="theReturnType">
<!--- Function definition goes here. --->
</cffunction>
<cffunction name="OnRequestStart">
<!--- OnRequestStart body goes here --->
<cfset Request.theFunctionName=This.theFunctionName>
</cffunction>
Functions that you define in this manner share the This scope and Variables scope with the Application.cfc file for the
request.
Setting application default variables and constants in onApplicationStart
You can set default variables and application-level constants in Application.cfc. For example, you can do the following:
246
Session resources include variables that store data that is needed throughout the session, such as account numbers,
shopping cart contents, or CFCs that contain methods and data that are used by multiple pages in a session.
Note: Do not include the cflogin tag or basic login processing in the onSessionStart method, as the code executes only
at the start of the session; it cannot handle user logout, and cannot fully ensure security.
Using the onSessionStart method
This method is useful for initializing session data, such as user settings or shopping cart contents, or for tracking the
number of active sessions. You do not need to lock the Session scope when you set session variables in this method.
For more information, see the onSessionStart entry in the CFML Reference.
Using the onSessionEnd method
Use this method for any clean-up activities when the session ends. (For information on ending sessions, see Ending
a session on page 315.) For example, you can save session-related data, such as shopping cart contents or information
about whether the user has not completed an order, in a database, or you can log the end of the session to a file. You
cannot use this method to display data on a user page, because it is not associated with a request.
Note: Sessions do not end, and the onSessionEnd method is not called when an application ends. For more information,
see the onSessionEnd entry in the CFML Reference.
implement an onRequest method, explicitly call the requested page in your onRequest method.
3 ColdFusion always processes onRequestEnd at the end of the request.
You can use each of the Application.cfc request methods to manage requests as follows:
Using the onRequestStart method
This method runs at the beginning of the request. It is useful for user authorization (login handling), and for requestspecific variable initialization, such as gathering performance statistics.
If you use the onRequestStart method and do not use the onRequest method, ColdFusion automatically processes
the request when it finishes processing the onRequestStart code.
Note: If you do not include an onRequest method in Application.cfm file, the onRequestStart method does not share
a Variables scope with the requested page, but it does share Request scope variables.
For more information, see the entry for onRequestStart in the CFML Reference
User authentication
When an application requires a user to log in, include the authentication code, including the cflogin tag or code that
calls this tag, in the onRequestStart method. Doing so ensures that the user is authenticated at the start of each
request. For detailed information on security and creating logins, see Securing Applications on page 339 For an
example that uses authentication code generated by the Adobe Dreamweaver CF Login Wizard, see onRequestStart in
the CFML Reference.
247
ColdFusion does not process the request unless you explicitly call it, for example, by using a cfinclude tag. This
behavior lets you use the onRequest method to filter requested page content or to implement a switch that
determines the pages or page contents to be displayed.
When you use cfinclude to process request, the CFC instance shares the Variables scope with the requested page.
As a result, any method in the CFC that executes can set the pages Variables scope variables, and the
onRequestEnd method can access any Variable scope values that the included page has set or changed. Therefore,
for example, the onRequestStart or onRequest method set variables that are used on the page.
To use this method as a filter, place the cfinclude tag inside a cfsavecontent tag, as the following example shows:
<cffunction name="onRequest">
<cfargument name = "targetPage" type="String" required=true/>
<cfsavecontent variable="content">
<cfinclude template=#Arguments.targetPage#>
</cfsavecontent>
<cfoutput>
#replace(content, "report", "MyCompany Quarterly Report", "all")#
</cfoutput>
</cffunction>
For more information, see the entry for onRequest in the CFML Reference
Using the onRequestEnd method
You use the onRequestEnd method for code that should run at the end of each request. (In ColdFusion versions
through ColdFusion MX 6.1, you would use the OnRequestEnd.cfm page for such code). Typical uses include
displaying dynamic footer pages. For an example, see onSessionEnd in the CFML Reference.
Note: If you do not include an onRequest method in Application.cfm file, the onRequestEnd method does not share a
Variables scope with the requested page, but it does share Request scope variables.
For more information, see the entry for onRequestEnd in the CFML Reference.
Use try/catch error handling in the event methods, such as onApplicationStart or onRequestStart, to handle
exceptions that happen in the event methods.
Implement the onError method. This method receives all exceptions that are not directly handled by try/catch
handlers in CFML code. The method can use the cfthrow tag to pass any errors it does not handle to ColdFusion
for handling.
Use cferror tags in the application initialization code following the cfcomponent tag, typically following the code
that sets the applications This scope variables. These tags specify error processing if you do not implement an
onError method, or if the onError method throws an error. You could implement an application-specific
validation error handler, for example, by placing the following tag in the CFC initialization code:
248
The ColdFusion default error mechanisms handle any errors that are not handled by the preceding techniques.
These mechanisms include the site-wide error handler that you specify in the ColdFusion Administrator and the
built-in default error pages.
These techniques let you include application-specific information, such as contact information or application or
version identifiers, in the error message, and let you display all error messages in the application in a consistent
manner. You use Application.cfc to develop sophisticated application-wide error-handling techniques, including
error-handling methods that provide specific messages, or use structured error-handling techniques.
Note: The onError method catches errors that occur in the onSessionEnd and onApplicationEnd application event
methods. It does not display messages to the user, however, because there is no request context. The onError function
logs errors that occur when the session or application ends.
Handling server-side validation errors in the onError method
Server-side validation errors are actually ColdFusion exceptions; as a result, if your application uses an onError
method, this method gets the error and must handle it or pass it on to ColdFusion for handling.
To identify a server-side validation error, search the Arguments.Exception.StackTrace field for
coldfusion.filter.FormValidationException. You can then handle the error directly in your onError routine, or throw
the error so that either the ColdFusion default validation error page or a page specified by an cferror tag in your
Application.cfc initialization code handles it.
Example: error Handling with the onError method
The following Application.cfc file has an onError method that handles errors as follows:
If the error is a server-side validation error, the onError method throws the error for handling by ColdFusion,
which displays its standard validation error message.
For any other type of exception, the onError method displays the name of the event method in which the error
occurred and dumps the exception information. In this example, because you generate errors on the CFM page
only, and not in a Application.cfc method, the event name is always the empty string.
249
<cfcomponent>
<cfset This.name = "BugTestApplication">
<cffunction name="onError">
<!--- The onError method gets two arguments:
An exception structure, which is identical to a cfcatch variable.
The name of the Application.cfc method, if any, in which the error
happened.
<cfargument name="Except" required=true/>
<cfargument type="String" name = "EventName" required=true/>
<!--- Log all errors in an application-specific log file. --->
<cflog file="#This.Name#" type="error" text="Event Name: #Eventname#" >
<cflog file="#This.Name#" type="error" text="Message: #except.message#">
<!--- Throw validation errors to ColdFusion for handling. --->
<cfif Find("coldfusion.filter.FormValidationException",
Arguments.Except.StackTrace)>
<cfthrow object="#except#">
<cfelse>
<!--- You can replace this cfoutput tag with application-specific
error-handling code. --->
<cfoutput>
<p>Error Event: #EventName#</p>
<p>Error details:<br>
<cfdump var=#except#></p>
</cfoutput>
</cfif>
</cffunction>
</cfcomponent>
To test this example, place a CFML page with the following code in the same page as the Application.cfc file, and enter
valid and invalid text in the text input field.
<cfform>
This box does Integer validation:
<cfinput name="intinput" type="Text" validate="integer" validateat="onServer"><br>
Check this box to throw an error on the action page:
<cfinput type="Checkbox" name="throwerror"><br>
<cfinput type="submit" name="submitit">
</cfform>
<cfif IsDefined("form.fieldnames")>
<cfif IsDefined("form.throwerror")>
<cfthrow type="ThrownError" message="This error was thrown from the bugTest action
page.">
<cfelseif form.intinput NEQ "">
<h3>You entered the following valid data in the field</h3>
<cfoutput>#form.intinput#</cfoutput>
</cfif>
</cfif>
Note: For more information on server-side validation errors, see Validating Data on page 743.
250
<cfcomponent>
<cfset This.name = "TestApplication">
<cfset This.Sessionmanagement=true>
<cfset This.Sessiontimeout="#createtimespan(0,0,10,0)#">
<cfset This.applicationtimeout="#createtimespan(5,0,0,0)#">
<cffunction name="onApplicationStart">
<cftry>
<!--- Test whether the DB that this application uses is accessible
by selecting some data. --->
<cfquery name="testDB" dataSource="cfdocexamples" maxrows="2">
SELECT Emp_ID FROM employee
</cfquery>
<!--- If we get database error, report it to the user, log the error
information, and do not start the application. --->
<cfcatch type="database">
<cfoutput>
This application encountered an error.<br>
Please contact support.
</cfoutput>
<cflog file="#This.Name#" type="error"
text="cfdocexamples DB not available. message: #cfcatch.message#
Detail: #cfcatch.detail# Native Error: #cfcatch.NativeErrorCode#">
<cfreturn False>
</cfcatch>
</cftry>
<cflog file="#This.Name#" type="Information" text="Application Started">
<!--- You do not have to lock code in the onApplicationStart method that sets Application
scope variables. --->
<cfscript>
Application.availableResources=0;
Application.counter1=1;
Application.sessions=0;
</cfscript>
<!--- You do not need to return True if you don't set the cffunction returntype attribute.
--->
</cffunction>
<cffunction name="onApplicationEnd">
<cfargument name="ApplicationScope" required=true/>
<cflog file="#This.Name#" type="Information"
text="Application #ApplicationScope.applicationname# Ended">
</cffunction>
<cffunction name="onRequestStart">
<!--- Authentication code, generated by the Dreamweaver Login Wizard,
makes sure that a user is logged in, and if not displays a login page. --->
<cfinclude template="mm_wizard_application_include.cfm">
<!--- If it's time for maintenance, tell users to come back later. --->
<cfscript>
if ((Hour(now()) gt 1) and (Hour(now()) lt 3)) {
WriteOutput("The system is undergoing periodic maintenance.
Please return after 3:00 AM Eastern time.");
return false;
} else {
this.start=now();
251
}
</cfscript>
</cffunction>
<cffunction name="onRequest">
<cfargument name = "targetPage" type="String" required=true/>
<cfsavecontent variable="content">
<cfinclude template=#Arguments.targetPage#>
</cfsavecontent>
<!--- This is a minimal example of an onRequest filter. --->
<cfoutput>
#replace(content, "report", "MyCompany Quarterly Report", "all")#
</cfoutput>
</cffunction>
<!--- Display a different footer for logged in users than for guest users or
users who have not logged in. --->
<cffunction name="onRequestEnd">
<cfargument type="String" name = "targetTemplate" required=true/>
<cfset theAuthuser=getauthuser()>
<cfif ((theAuthUser EQ "guest") OR (theAuthUser EQ ""))>
<cfinclude template="noauthuserfooter.cfm">
<cfelse>
<cfinclude template="authuserfooter.cfm">
</cfif>
</cffunction>
<cffunction name="onSessionStart">
<cfscript>
Session.started = now();
Session.shoppingCart = StructNew();
Session.shoppingCart.items =0;
</cfscript>
<cflock timeout="5" throwontimeout="No" type="EXCLUSIVE" scope="SESSION">
<cfset Application.sessions = Application.sessions + 1>
</cflock>
<cflog file="#This.Name#" type="Information" text="Session:
#Session.sessionid# started">
</cffunction>
<cffunction name="onSessionEnd">
<cfargument name = "SessionScope" required=true/>
<cflog file="#This.Name#" type="Information" text="Session:
#arguments.SessionScope.sessionid# ended">
</cffunction>
<cffunction name="onError">
<cfargument name="Exception" required=true/>
<cfargument type="String" name = "EventName" required=true/>
<!--- Log all errors. --->
<cflog file="#This.Name#" type="error" text="Event Name: #Eventname#">
<cflog file="#This.Name#" type="error" text="Message: #exception.message#">
252
Replace the cfapplication tag with CFC initialization code that sets the Application.cfc This scope variables that
correspond to the tag attributes.
Place in the onApplicationStart method, any code that initializes Application scope variables, and any other
application-specific code that executes only when the application starts. Often, such code in Application.cfm is
inside a block that tests for the existence of an Application scope switch variable. Remove the variable test and the
Application scope lock that surrounds the code that sets the Application scope variables.
Place in the onSessionStart method, any code that initializes Session scope variables, and any other applicationspecific code that executes only when the session starts. Remove any code that tests for the existence of Session
scope variables to be for initialized and the Session scope lock that surrounds the code that sets the Session scope
variables.
Place in the onRequestStart method, any cflogin tag and related authentication code.
Place in the onRequest method, any code that sets Variables scope variables and add a cfinclude tag that includes
the page specified by the Arguments of the method.Targetpage variable.
Place in the onRequestEnd method, any code you have in an OnRequestEnd.cfm page.
Consider replacing cferror tags with an onError event method. If you do not do so, place the cferror tags in the
CFC initialization code.
253
Note: The value that you set for the name attribute in the cfapplication tag is limited to 64 characters.
Set application-specific time-outs for Application and Session scope variables. These settings override the default
values set in the ColdFusion Administrator.
Specify a storage method for Client scope variables. This setting overrides the method set in the ColdFusion
Administrator.
A data source
A domain name
Style settings, such as fonts or colors
Other important application-level variables
Often, an Application.cfm page uses one or more cfinclude tags to include libraries of commonly used code, such as
user-defined functions, that are required on many of the applications pages.
Processing logins
When an application requires a user to log in, you typically place the cflogin tag on the Application.cfm page. For
detailed information on security and creating logins, including an Application.cfm page that manages user logins, see
Securing Applications on page 339
254
Handling errors
Use the cferror tag on your Application.cfm page to specify application-specific error-handling pages for request,
validation, or exception errors, as shown in the following example. This way you include application-specific
information, such as contact information or application or version identifiers, in the error message, and you display
all error messages in the application in a consistent manner.
For more information on error pages and error handling, see Handling Errors on page 275.
255
</cfif>
</cflock>
</cfif>
<!--- Set a Session variable.--->
<cflock timeout="20" scope="Session" type="exclusive">
<cfif not IsDefined("session.pagesHit")>
<cfset session.pagesHit=1>
<cfelse>
<cfset session.pagesHit=session.pagesHit+1>
</cfif>
</cflock>
<!--- Set Application-specific Variables scope variables. --->
<cfset mainpage = "default.cfm">
<cfset current_page = "#cgi.path_info#?#cgi.query_string#">
<!--- Include a file containing user-defined functions called throughout
the application. --->
<cfinclude template="commonfiles/productudfs.cfm">
Description
<cfapplication name="Products"
clientmanagement="Yes"
clientstorage="myCompany"
sessionmanagement="Yes">
<cfsetting showDebugOutput="No">
<cferror type="request"
template="requesterr.cfm"
mailto="[email protected]">
<cferror type="validation"
template="validationerr.cfm">
Sets the Application scope variables, if they are not already set. For a
detailed description of the technique used to set the Application
scope variables, see Using Persistent Data and Locking on page 301.
Sets the Session scope pagesHit variable, which counts the number
of pages touched in this session. If the variable does not exist, creates
it; otherwise, increments it.
Sets two Variables scope variables that are used throughout the
application. Creates the current_page variable dynamically; its value
varies from request to request.
<cfinclude template="commonfiles/productudfs.cfm">
256
Whether to cache the page results on the server, the client system, or both. The default is both. The default is
optimal for pages that are identical for all users. If the pages contain client-specific information, or are secured with
ColdFusion user security, set the action attribute in the cfcache tag to ClientCache.
The directory on the server in which to store the cached pages. The default directory is cf_root/cache. It is a good
practice to create a separate cache directory for each application. Doing so prevents the cfcache tag flush action
from inappropriately flushing more than one applications caches at a time.
The time span that indicates how long the page lasts in the cache from when it is stored until it is automatically
flushed.
You can also specify several attributes for accessing a cached page on the web server, including a user name and
password (if required by the web server), the port, and the protocol (HTTP or HTTPS) to use to access the page.
257
Place the cfcache tag before any code on your page that generates output, typically at the top of the page body. For
example, the following tag tells ColdFusion to cache the page on both the client and the server. On the server, the page
is cached in the e:/temp/page_cache directory. ColdFusion retains the cached page for one day.
<cfcache timespan="#CreateTimespan(1, 0, 0, 0)#" directory="e:/temp/page_cache">
Important: If an Application.cfm or Application.cfc page displays text (for example, if it includes a header page), use the
cfcachetag on the Application.cfm page, in addition to the pages that you cache. Otherwise, ColdFusion displays the
Application.cfm page output twice on each cached page.
Flushing cached pages
ColdFusion automatically flushes any cached page if you change the code on the page. It also automatically flushes
pages after the expiration time span passes.
Use the cfcache tag with the action="flush" attribute to immediately flush one or more cached pages. You can
optionally specify the directory that contains the cached pages to be flushed and a URL pattern that identifies the pages
to flush. If you do not specify a URL pattern, all pages in the directory are flushed. The URL pattern can include asterisk
(*) wildcards to specify parts of the URL that can vary.
When you use the cfcache tag to flush cached pages, ColdFusion deletes the pages cached on the server. If a flushed
page is cached on the client system, it is deleted, and a new copy gets cached the next time the client tries to access the
ColdFusion page.
The following example flushes all the pages in the e:/temp/page_cache/monthly directory that start with HR:
<cfcache action="flush" directory="e:/temp/page_cache/monthly" expirURL="HR*">
If you have a ColdFusion page that updates data that you use in cached pages, the page that does the updating includes
a cfcache tag that flushes all pages that use the data.
For more information on the cfcache tag, see the CFML Reference.
258
In this example, the highlighted code creates a page fragment that displays all art records from the table art. The cache
is set to expire either after one hour or after an idle time of 30 minutes. After the cache is invalidated, cache is recreated
the next time the page is accessed thereby displaying updated information (if any).
Accessing Amazon S3
Use either of the following URL formats to access Amazon S3 from ColdFusion:
s3://bucket/x/y/sample.txt
Here, bucket is the name of the bucket and the remaining portion of the URL is the key name of the Amazon S3
object.
In this case, specify the following authentication information in the Application.cfc:
259
<cfscript>
this.name ="Object Operations";
this.s3.accessKeyId = "key_ID";
this.s3.awsSecretKey = "secret_key";
this.s3.defaultLocation="location";
</cfscript>
For example,
<cffile action="write" output="S3 Specification" file="s3://testbucket/sample.txt"/>
s3://accessKeyId:awsSecretKey@bucket/x/y/sample.txt
Note: If you have specified the accessKeyID and awsSecretKey in both the URL and Application.cfc, then value
specified in the URL takes precedence.
Example
<cffile action="write" output="S3 Specifications"
file="s3://accessKeyID:awsSecretKey@bucket/x/y/sample.txt"/>
Supported operations
The following are the supported operations on Amazon S3:
Bucket operations
Use the cfdirectory tag or the directory functions to perform the bucket operation (create, delete, or list).
260
Operation
Tag used
Function
Example
Create
cfdirectory
action="create"
DirectoryC
reate
DirectoryL
ist
cfdirectory
action="list"
Since Amazon S3 does not have the concept of directory, it returns the key
name (that is, the full path) of objects contained in the bucket.
Directory attribute in this case takes the path, for example, s3://bucket1
in which objects have to be searched. The path that follows the bucket name
is used as a prefix to perform the list operation and all the objects that match
the prefix are returned.
In this case, the following attributes are ignored: recurse, type, and sort.
Delete
cfdirectory
action="delete"
DirectoryD
elete
Note: To verify if the bucket exists and is accessible, use the function directoryExists.
Object operations
All object operations are similar to file operations (read, write, copy, and delete). Therefore, the tag cffile and the
file functions can be used to perform the operations. The following table describes the common scenarios:
Operation
Tag used
Function
Example
Read
cffile
action="read"
FileRead
Write
cffile
action="write"
FileWrite
Delete
cffile
action="delete"
FileDelete
Copy
cffile
action="copy"
FileCopy
261
FileIsEOF
FileReadBinary
Filecopy
FileReadLine
FileExists
FileWriteln
FileOpen
FileClose
FileRead
FileDelete
Example
<cfdirectory action="create"
directory="s3://<bucketname>"
storelocation="US">
<cfdirectory action="create"
directory="s3://<bucketname>"
storelocation="EU">
storeACL
group
email
canonical (ID)
The following are the possible permissions:
read
write
read_acp
write_acp
full_control
See Amazon S3 ACL Documentation for more details.
262
ACLObject
ACLObject is an array of struct where each struct represents an ACL grant. The grantee details are as follows:
group Must have the keys Group (with value all, authenticated, or log_delivery) and permission.
email Must have the keys email and permission.
canonical Must have the keys Id and permission. displayName is optional.
Sample ACLObject
all_read = {group="all", permission="read"};
owner_full = {email="[email protected]", permission="full_control"};
aclObj = [owner_full, all_read];
Parameters
Parameter
Description
url
ACLObject
An array of struct where each struct represents a permission or grant as discussed in ACLObject on page 262.
History
ColdFusion 9 Update 1: Added this function
Usage
Use this function to set full permission. The function overwrites all existing permissions. Only the ones you set in the
current context exist.
263
Example
<cftry>
<cfset dir = "s3://bucket_name">
<cfif !directoryExists(dir)>
<cfset directorycreate(dir)>
</cfif>
<cfset
<cfset
<cfset
<cfset
<cfset
<cfset
<cfset
<cfset
<cfset
perm = structnew()>
perm.group = "all">
perm.permission = "read">
perm1 = structnew()>
perm1.email = "email ID">
perm1.permission = "FULL_CONTROL">
myarrray = arrayNew(1)>
myarrray = [perm,perm1]>
fileWrite("#dir#/test.txt","This is to test all users permission")>
<cfset StoreSetACL("#dir#/textl.txt","#myarrray#")>
<cfset test = StoreGetACL ("#dirkey#/test.txt") >
<cfdump var= "test">
<cfcatch>
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
storeAddACL
Description
Adds ACL to existing ACL for object or bucket.
Returns
Nothing
Syntax
StoreAddACL(url, ACLObject)
Parameters
Parameter
Description
url
ACLObject
An array of struct where each struct represents a permission or grant as discussed in ACLObject on page 262.
History
ColdFusion 9 Update 1: Added this function
Usage
Use this function to add permissions to the existing ones.
264
Example
<cftry>
<cfset dir = "s3://bucket_name/">
<cfset perm = structnew()>
<cfset perm.group = "authenticated">
<cfset perm.permission = "READ">
<cfset perm1 = structnew()>
<cfset perm1.email = "email_ID">
<cfset perm1.permission = "READ_ACP">
<cfset myarrray = [perm,perm1]>
<cfif NOT DirectoryExists(dir)>
<cfset directoryCreate(dir)>
</cfif>
<cfset fileWrite("#dir#/Sample.txt","This is to test StoreAddACL")>
<cfset StoreAddACL("#dir#","#myarrray#")>
<cfset test = StoreGetACL(dirkey)>
<cfdump var="#test#">
<cfcatch>
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
storeGetACL
Description
Gets the ACL object or bucket.
Returns
Returns an ACLObject
Syntax
StoreGetACL(url, ACLObject)
Parameters
Parameter
Description
url
ACLObject
An array of struct where each struct represents a permission or grant as discussed in ACLObject on page 262.
History
ColdFusion 9 Update 1: Added this function
Example
<cfset dir = "s3://bucket_Name">
<cfif NOT DirectoryExists(dir)>
<cfset directoryCreate(dir)>
</cfif>
<cfset test = StoreGetACL("#dir#")>
<cfdump var="#test#">
265
Using metadata
Amazon S3 allows you to specify metadata for both objects and buckets.
The following two functions let you get and set the metadata on objects or buckets.
StoreGetMetadata
Description
Returns the metadata related to the object or bucket.
Returns
Object metadata or bucket metadata
Syntax
StoreGetMetadata(url)
Parameters
Parameter
Description
url
History
ColdFusion 9 Update 1: Added this function
Example
<cfdump var = #StoreGetMetadata("bucket_Name")#>
StoreSetMetadata
Description
Sets the metadata on bucket or object.
Returns
Nothing
Syntax
StoreSetMetadata(url,Struct)
Parameters
Parameter
Description
url
struct
Represents the metadata. See Standard keys on page 266 for a list of standard keys in metadata.
You can also have custom metadata apart from the standard ones.
266
History
ColdFusion 9 Update 1: Added this function
Example
<cfscript>
mydate = #Now()#;
hello = structNew();
hello.color = "grey";
/cfscript>
<cfset dir = "s3://mycfbucket">
<cffile action="write" file="#dir#/hello5.txt" output="Sample s3 text">
<cfset StoreSetMetadata("#dir#/hello5.txt","#hello#")>
<cfset test = StoreGetMetadata("#dir#/hello5.txt")>
<cfdump var="#test#">
Standard keys
The following are the standard keys in the metadata:
For objects
last_modified
date
owner
etag
content_length
content_type
content_encoding
content_disposition
content_language
content_md5
md5_hash
For buckets
date
owner
Security considerations
Sandboxing is not applicable to S3 buckets or objects as Amazon S3 has its own security features that take care of it.
Supported functions
fileOpen
fileExists
fileRead
getFileInfo
fileClose
fileisEOF
fileReadBinary
getDirectoryFromPath
fileCopy
fileMove
fileReadLine
directoryCreate
fileDelete
fileWrite
fileSetLastModified
directoryDelete
267
directoryExists
imageWrite
directoryList
imageWriteBase64
imageNew
isImageFile
imageRead
isPDFFile
cfdocument
cffeed
cfftp
cfimage
cfloop
Supported tags
Limitations
The following tags are not supported:
cfpdf
cfpdfform
When S3 object is used as output for outputfile attribute of cfexecute tag, it results in an error Timeout
period expired without completion of <exe>. It also results in a NullPointerException at server console.
To use the function fileMove, the source and destination objects must have the same bucket name. That is,
you cannot move Amazon S3 objects across buckets or to other file systems.
The following sample syntax explains how to use the in-memory CFM file:
For tags that take logical path, define mapping in Administrator. Execute in-memory CFM pages using the
cfinclude tag:
<cfinclude template="/inmemory/filename.cfm">
Create a mapping for ram:/// so that it can be used in the tags. In this example, /inmemory is the mapping that
points to ram:///.
For tags that take absolute path, specify the syntax as provided in the following example:
<cffile action="append" file="ram:///a/b/dynamic.cfm" output="I'm appending">
Note: You cannot have Application.cfm as an in-memory file. If you have one, it is ignored.
268
Example
The following code describes how to write an image as an in-memory file:
<cffile action="readBinary" variable="myImage" file="#ExpandPath('./')#/blue.jpg">
<cffile action="write" output="#myImage#" file="ram:///a.jpg">
<cfif FileExists("ram:///a.jpg")>
<cfoutput>a.jpg exists</cfoutput>
<cfelse>
<cfoutput>a.jpg Doesn't exists</cfoutput>
</cfif>
The following sample syntax explains how you can instantiate the in-memory CFC file:
<cfset cfc=CreateObject("component","inmemory.filename")/>
Example
The following code writes a CFC as in-memory file:
<cffile action="read" file="#ExpandPath('./')#/dynamic.cfc" variable="Message">
<cffile action="write" file="ram:///cfc/dynamic.cfc" output="#Message#">
If a CFC extends another CFC in the same directory in RAM, you can use relative path. For instance, if a.cfc and
b.cfc belong to the same directory in RAM, a.cfc can extend b.cfc using relative path as shown in the following code:
<cfcomponent name="a" extends"b">
</cfcomponent>
You can use in-memory ColdFusion interfaces in the same way as you use in-memory CFCs.
269
Supported functions
The following file functions are supported for in-memory files:
FileIsEOF
FileReadBinary
Filemove
Filecopy
FileReadLine
FileExists
FileOpen
FileWriteln
FileClose
FileRead
FileDelete
DirectoryExists
FileSetLastModified
GetFileInfo
GetDirectoryFromPath
GetFileFromPath
ImageNew
ImageRead
ImageWrite
ImageWriteBase64
IsImageFile
IsPDFFile
FileSetLastModified
Example
The following syntax explains the function FileSetLastModified()
<cftry>
<cffile action="write" file="ram:///a.txt" output="Testing the function FileSetLastModified">
<cfset date="12/12/2007">
<cfscript>
FileSetLastModified("ram:///a.txt", "#date#");
sleep(1000);
WriteOutput(#GetFileInfo("ram:///a.txt").lastmodified#);
</cfscript>
<cfcatch>
<cfset PrintException(cfcatch)>
</cfcatch>
</cftry>
<cf_expectedresults>{ts '2007-12-12 00:00:00'}
</cf_expectedresults>
270
File operations
The following file operations are supported for in-memory files:
Custom tags
In-memory CFM pages and CFCs can call custom tags but the custom tags must be present in disk. In-memory custom
tags are not supported.
cfcontent
cfdocument
cfdump
cfexchange
cfexecute
cffeed
cfhttp
cfftp
cfimage
cfloop
271
cfpresentation
cfprint
cfreport
cfzip
Example using the tag cfcontent
<cfcontent file="ram:///a.jpg" type="image/jpeg" deletefile="yes">
Adding permissions
ColdFusion lets you add permissions for directories/files on RAM using an existing sandbox security setup. You can
only set up sandbox security for disk directories and not for RAM directories. Access to an in-memory directory/file
can be restricted only through an existing local file system sandbox.
Therefore, to set up sandbox security for in-memory files, select a sandbox that you have already configured for a disk
directory.
By default the ram:/// directories are included in the list of secured folders and have read, write, execute, and delete
permissions set. Therefore, all RAM files have permissions by default in a sandbox. All the security restrictions that
apply to disk files apply to in-memory files.
To set up Sandbox security for in-memory files,
1 Open the Security > Sandbox Security page in the ColdFusion Administrator.
4 Select the required permissions, click Add Files/Paths, and then click Finish.
For further details on sandbox security, refer to the ColdFusion Administration Guide.
272
Limitations
File names/Directory names on RAM are case sensitive.
In-memory files must be accessed using mapping or absolute path. Relative paths to files/directories are not
supported.
Correct: ram:///a/b/
Incorrect: ram:///a/b/../..
You cannot access in-memory files using HTTP/HTTPS protocols. Instead, use ram:///<file>. For example,
ram:///a/b/test.cfm.
The cfimport tag does not accept tag libraries on RAM. For instance, the following does not work:
<cfimport prefix="custom" taglib="ram:///a/b/mytags.jar">
Renaming across file systems (as shown in the following syntax) is not supported.
<cffile action="rename" source="ram:///src1/message2.txt"
destination="#ExpandPath('./')#/123.txt">.
For the cfexecute tag, the executable cannot be on RAM and must be on your local file system. But the output
can be an in-memory file as illustrated in the following code:
<cfexecute name="C:\WINDOWS\System32\netstat.exe" arguments="-e"
outputFile="ram:///output.txt" timeout="1">
</cfexecute>
<cfset thisPath=ExpandPath("*.*")>
273
274
Description
Gets two record sets from the stored procedure: the first
and third result sets it returns.
<cfoutput>
The output param value: '#foo#'<br>
</cfoutput>
For more information on creating stored procedures, see your database management software documentation. For
more information on using the cfstoredproc tag, see the CFML Reference.
Using the cfquery tag cachedWithin attribute
The cfquery tag cachedWithin attribute tells ColdFusion to save the results of a database query for a specific period
of time. This way, ColdFusion accesses the database on the first page request, and does not query the database on
further requests until the specified time expires. Using the cachedWithin attribute significantly limits the overhead of
accessing databases that do not change rapidly.
This technique is useful if the database contents only change at specific, known times, or if the database does not
change frequently and the purpose of the query does not require up- to-date results.
Use the CreateTimeSpan function to specify the cachedWithin attribute value (in days, hours, minutes, seconds
format). For example, the following code caches the results of getting the contents of the Employees table of the
cfdocexamples data source for one hour.
275
Handling Errors
Adobe ColdFusion includes many tools and techniques for responding to errors that your application encounters.
These tools include error handling mechanisms and error logging tools.
For information on user input validation, see Introduction to Retrieving and Formatting Data on page 703 and
Building Dynamic Forms with cfform Tags on page 722 For information on debugging, see Debugging and
Troubleshooting Applications on page 378.
Specify custom pages for ColdFusion to display in each of the following cases:
When a ColdFusion page is missing (the Missing Template Handler page)
When an otherwise-unhandled exception error occurs during the processing of a page (the Site-wide Error
Handler page)
You specify these pages on the Settings page in the Server Settings page in the ColdFusion Administrator; for more
information, see the ColdFusion Administrator Help.
Use the cferror tag to specify ColdFusion pages to handle specific types of errors.
Use the cftry, cfcatch, cfthrow, and cfrethrow tags to catch and handle exception errors directly on the page
where they occur.
Log errors. ColdFusion logs certain errors by default. You can use the cflog tag to log other errors.
The following information is detailed in the next few topics:
The basic building blocks for understating types of ColdFusion errors and how ColdFusion handles them
Last updated 1/20/2012
276
Understanding errors
You can look at errors in many ways; for example, you can look at errors by their causes. You can also look at them by
their effects, particularly by whether your application can recover from them. You can also look at them the way
ColdFusion does, as follows:
Description
Program errors
Can be in the code syntax or the program logic. The ColdFusion compiler identifies and reports program syntax
errors when it compiles CFML into Java classes. Errors in your application logic are harder to locate. For
information on debugging tools and techniques, see Debugging and Troubleshooting Applications on
page 378.
Unlike ColdFusion syntax errors, SQL syntax errors are only caught at runtime.
Data errors
Are typically user data input errors. You use validation techniques to identify errors in user input data and enable
the user to correct the errors.
System errors
Can come from a variety of causes, including database system problems, time-outs due to excessive demands on
your server, out-of-memory errors in the system, file errors, and disk errors.
Although these categories do not map completely to the way ColdFusion categorizes errors they provide a useful way
of thinking about errors and can help you in preventing and handling errors in your code.
277
Type
Description
Exception
An error that prevents normal processing from continuing. All ColdFusion exceptions are, at their
root, Java exceptions.
Missing template
An HTTP request for a ColdFusion page that cannot be found. Generated if a browser requests a
ColdFusion page that does not exist.
Missing template errors are different from missing include exceptions, which result from
cfinclude tags or custom tag calls that cannot find their targets.
Server-side form field validation errors are a special kind of ColdFusion exception. You specify serverside form validation by using cfform attributes or hidden HTML form fields. All other types of serverside validation, such as the cfparam tag generate runtime exceptions. For more information on
validating form fields see Validating Data on page 743.
ColdFusion includes a built-in error page for server-side form field validation errors, and the cferror
tag includes a type attribute that lets you handle these errors in a custom error page, but if you use
onError processing in Application.cfc, or try/catch error handling, the error appears as an Application
exception. For more information on handling Form field validation in Application.cfc see Handling
server-side validation errors in the onError method on page 248.
Note: The onSubmit and onBlur form field validation techniques use JavaScript or Flash validation on the client browser.
Error responses from external services, such as an ODBC driver or CORBA server
CFML errors or the results of cfthrow or cfabort tags
Internal errors in ColdFusion
278
Basic
Custom
Advanced
Java class
Note: Use only custom error type names and the Application basic type name in cfthrow tags. All other built-in
exception type names identify specific types of system-identified errors, so do not use them for errors that you identify
yourself.
Basic exception types
All ColdFusion exceptions except for custom exceptions belong to a basic type category. These types consist of a
broadly defined categorization of ColdFusion exceptions. The following table describes the basic exception types:
Type
Type name
Description
Database failures
Database
MissingInclude
Template errors
Template
Object exceptions
Object
Security exceptions
Security
Expression exceptions
Expression
Failed expression evaluations; for example, if you try to add 1 and "a".
Locking exceptions
Lock
SearchEngine
Application-defined exception
events raised by cfthrow
Application
All exceptions
Any
Any exceptions. Includes all types in this table and any exceptions that
are not handled in another error handler, including unexpected
internal and external errors.
Note: The Any type includes all error with the Java object type of java.lang.Exception. It does not include
java.lang.Throwable errors. To catch Throwable errors, specify java.lang.Throwable in the cfcatch tag type attribute.
279
Custom exceptions
You can generate an exception with your own type by specifying a custom exception type name, for example
MyCustomErrorType, in a cfthrow tag. You then specify the custom type name in a cfcatch or cferror tag to
handle the exception. Custom type names must be different from any built-in type names, including basic types and
Java exception classes.
Advanced exception types
The Advanced exceptions consist of a set of specific, narrow exception types. These types are supported in ColdFusion
for backward-compatibility.
Java exception classes
Every ColdFusion exception belongs to, and is identified by, a specific Java exception class in addition to its basic,
custom, or advanced type. The first line of the stack trace in the standard error output for an exception identifies the
Java class of the exception.
For example, if you attempt to use an array function such as ArrayIsEmpty on an integer variable, ColdFusion
generates an exception that belongs to the Expression exception basic type and the
coldfusion.runtime.NonArrayException Java class.
In general, most applications do not use Java exception classes to identify exceptions. However, you can use Java class
names to catch exceptions in non-CFML Java objects; for example, the following line catches all Java input/output
exceptions:
<cfcatch type="java.io.IOException">
280
If the error occurs on a page that is accessed by a cfinclude or cfmessagebox tag, or on a custom tag page that
you access using the cf_ notation, ColdFusion handles it as a runtime exception in the page that accesses the tag.
For a description of how these errors are handled, see the next section, Runtime exception errors.
If the error occurs directly on the requested page, and the Administrator Settings Site-wide Error Handler field
specifies an error handler page, ColdFusion displays the specified error page. Otherwise, ColdFusion reports the
error using the standard error message format described in Error messages and the standard error format on
page 280.
Runtime exception errors
If ColdFusion encounters a runtime exception, it does the action for the first matching condition in the following table:
Condition
Action
The code with the error is inside a cftry tag and the exception type is Executes the code in the cfcatch tag.
specified in a cfcatch tag.
If the cftry block does not have a cfcatch tag for this error, tests for
an appropriate cferror handler or site-wide error handler.
The ColdFusion application has an Application.cfc with an onError
method
A cferror tag specifies an exception error handler for the exception Uses the error page specified by the cferror tag.
type.
The Administrator Settings Site-wide Error Handler field specifies an
error handler page.
For example, if an exception occurs in CFML code that is not in a cftry block, and Application.cfc does not have an
onError method, but a cferror tag specifies a page to handle this error type, ColdFusion uses the specified error page.
281
Section
Description
Error description
Error message
A detailed description of the error. The error message diagnostic information displayed depends on the type of
error. For example, if you specify an invalid attribute for a tag, this section includes a list of all valid tag attributes.
Error location
The page and line number where ColdFusion encountered the error, followed by a short section of your CFML that
includes the line. This section does not display for all errors.
In some cases, the cause of an error can be several lines above the place where ColdFusion determines that there
is a problem, so the line that initially causes the error might not be in the display.
Resources
Links to documentation, the Knowledge Base, and other resources that can help you resolve the problem.
Error environment
information
Information about the request that caused the error. All error messages include the following:
Stack trace
User browser
User IP address
The Java stack at the time of the exception, including the specific Java class of the exception. This is helpful if you
must contact Adobe Technical Support.
The stack trace is collapsed by default. Click the heading to display the trace.
If you get a message that does not explicitly identify the cause of the error, check the key system parameters, such as
available memory and disk space.
(In this code, the Replace function removes the leading slash sign from the script name to make the display more
friendly.)
282
Use
cftry
Place cftry blocks around specific code sections where exceptions can be expected and you want to handle
those exceptions in a context-specific manner; for example, if you want to display an error message that is specific
to that code.
Use cftry blocks where you can recover from an exception. For example, you can retry an operation that times
out, or access an alternate resource. You can also use the cftry tag to continue processing where a specific
exception does not harm your application; for example, if a missing resource is not required.
For more information, see Handling runtime exceptions with ColdFusion tags on page 287.
Application.cfc onError
method
Implement the onError method in your Application.cfc to consistently handle application-specific exceptions
that are generated by multiple code sections in the application. For more information on error handling using
Application.cfc, see Handling errors in Application.cfc on page 247.
283
Technique
Use
Use the cferror tag to specify error pages for specific exception types. These pages cannot recover from errors,
but they can provide the user with information about the cause of the error and the steps to take to prevent the
problem.
For more information, see Specifying custom error messages with the cferror tag on page 283.
error page
Use the cferror tag to specify a Request error handler that provides a customized, application-specific message
for unrecoverable exceptions. Place the tag in the Application.cfc initialization code or on the Application.cfm
page to make it apply to all pages in an application.
A Request error page cannot use CFML tags, but it can display error variables. As a result, you can use it to display
common error information, but you cannot provide error-specific instructions. Typically, Request pages display
error variable values and application-specific information, including support contact information.
For example code, see Example of a request error page section.
Specify a site-wide error handler in the Administrator to provide consistent appearance and contents for all
otherwise-unhandled exceptions in all applications on your server.
Like the Request page, the site-wide error handler cannot perform error recovery. However, it can include CFML
tags in addition to the error variables.
Because a site-wide error handler prevents ColdFusion from displaying the default error message, it allows you to
limit the information reported to users. It also lets you provide all users with default contact information or other
instructions.
Description
Validation
Handles server-side form field data validation errors. The validation error page cannot include CFML tags, but it
can display error page variables.
You can use this attribute only in the Application.cfc initialization code or on the Application.cfm page. It has no
effect when used on any other page. Therefore, you can specify only one validation error page per application,
and that page applies to all server-side validation errors.
Exception
Handles specific exception errors. You can specify individual error pages for different types of exceptions.
Request
Handles any exception that is not otherwise-handled. The request error page runs after the CFML language
processor finishes. As a result, the request error page cannot include CFML tags, but can display error page
variables. A request error page is useful as a backup if errors occur in other error handlers.
284
Attribute
Description
Type
The type of error that causes ColdFusion to display this page: Exception, Request, or Validation.
Exception
Use only for the Exception type. The specific exception or exception category that causes the page to display. This
attribute can specify any of the types described in About ColdFusion exceptions on page 277.
Template
MailTo
(Optional) An e-mail address. The cferror tag sets the error page error.mailTo variable to this value. The error
page can use the error.mailTo value in a message that tells the user to send an error notification. ColdFusion
does not send any message itself.
The following cferror tag specifies a custom error page for exceptions that occur in locking code and informs the
error page of the e-mail address to use to send a notification each time this type of error occurs:
<cferror type = "exception"
exception = "lock"
template = "../common/lockexcept.cfm"
mailto = "[email protected]">
For detailed information on the cferror tag, see the CFML Reference.
Considerations
Validation
Can use nine CFML error variables, such as Error.Diagnostics, by enclosing them with number signs.
Can use full CFML syntax, including tags, functions, and variables.
Can use nine standard CFML Error variables and cfcatch variables. Use either Error or cferror as the prefix
for both types of variables.
Request
Exception
The following table describes the variables available on error pages: Exception error pages can also use all of the
exception variables listed in the section Exception information in cfcatch blocks on page 289. To use these variables,
replace the cfcatch prefix with cferror or error. For example, to use the exception message in an error page, refer
to it as error.message.
285
In general, production Exception and Request pages should not display detailed error information, such as that
supplied by the error.diagnostics variable. Typically, Exception pages e-mail detailed error information to an
administrative address or log the information using the cflog tag instead of displaying it to the user. For more
information on using the cflog tag, see Logging errors with the cflog tag on page 285.
Example of a request error page
The following example shows a custom error page for a request error:
<html>
<head>
<title>Products - Error</title>
</head>
<body>
<h2>Sorry</h2>
<p>An error occurred when you requested this page.</p>
<p>Please send e-mail with the following information to #error.mailTo# to report
this error.</p>
<table border=1>
<tr><td><b>Error Information</b> <br>
Date and time: #error.DateTime# <br>
Page: #error.template# <br>
Remote Address: #error.remoteAddress# <br>
HTTP Referer: #error.HTTPReferer#<br>
</td></tr></table>
<p>We apologize for the inconvenience and will work to correct the problem.</p>
</body>
</html>
286
ColdFusion automatically logs errors to the default logs if you use the default error handlers. In all other cases, use the
cflog tag in your error handling code to generate log entries.
The cflog tag lets you specify the following information:
A custom file or standard ColdFusion log file in which to write the message.
Text to write to the log file. This can include the values of all available error and cfcatch variables.
Message severity (type): Information Warning, Fatal, or Error.
Whether to log any of the following: application name, thread ID, system date, or system time. By default, all get
logged.
For example, you could use a cflog tag in an exception error-handling page to log the error information to an
application-specific log file, as in the following page:
<html>
<head>
<title>Products - Error</title>
</head>
<body>
<h2>Sorry</h2>
<p>An error occurred when you requested this page.
The error has been logged and we will work to correct the problem.
We apologize for the inconvenience. </p>
<cflog type="Error"
file="myapp_errors"
text="Exception error -Exception type: #error.type#
Template: #error.template#,
Remote Address: #error.remoteAddress#,
HTTP Reference: #error.HTTPReferer#
Diagnostics: #error.diagnostics#">
</body>
</html>
Description
<cflog type="Error"
file="myapp_errors"
text="Exception error -Exception type: #error.type#
Template: #error.template#,
Remote Address: #error.remoteAddress#,
HTTP Reference: #error.HTTPReferer#
Diagnostics: #error.diagnostics#">
A log file entry like the following is generated if you try to call a nonexistent custom tag and this page catches the error
(line breaks added for clarity):
287
Respond appropriately to specific errors within the context of the current application page
Recover from errors whenever possible.
Exception-handling tags
ColdFusion provides the exception-handling tags listed in the following table:
Tag
Description
cftry
If any exceptions occur while processing the tag body, look for a cfcatch tag that handles the exception, and
execute the code in the cfcatch tag body.
cfcatch
Execute code in the body of this tag if the exception caused by the code in the cftry tag body matches the
exception type specified in this tags attributes.
Used in cftry tag bodies only.
cfthrow
cfrethrow
Exit the current cfcatch block and generates a new exception of the same type.
Used only in cfcatch tag bodies.
288
You can include code that recovers from errors so your application can continue processing without alerting the
user.
You can create customized error messages that apply to the specific code that causes the error.
For example, you can use cftry to catch errors in code that enters data from a user registration form to a database.
The cfcatch code could do the following:
1 Retry the query, so the operation succeeds if the resource was only temporarily unavailable.
2 If the retries fail:
The cfcatch tags must follow all other code in a cftry tag body.
You can nest cftry blocks. For example, the following structure is valid:
289
<cftry>
code that may cause an exception
<cfcatch ...>
<cftry>
First level of exception handling code
<cfcatch ...>
Second level of exception handling code
</cfcatch
</cftry>
</cfcatch>
</cftry>
If an exception occurs in the first level of exception-handling code, the inner cfcatch block can catch and handle
it. (An exception in a cfcatch block cannot be handled by cfcatch blocks at the same level as that block.)
ColdFusion always responds to the latest exception that gets raised. For example, if code in a cftry block causes
an exception that gets handled by a cfcatch block, and the cfcatch block causes an exception that has no handler,
ColdFusion displays the default error message for the exception in the cfcatch block, and you are not notified of
the original exception.
If an exception occurs when the current tag is nested inside other tags, the CFML processor checks the entire stack
of open tags until it finds a suitable cftry/cfcatch combination or reaches the end of the stack.
Use cftry with cfcatch to handle exceptions based on their point of origin within an application page, or based
on diagnostic information.
The entire cftry tag, including all its cfcatch tags, must be on a single ColdFusion page. You cannot place the
<cftry> start tag on one page and have the </cftry> end tag on another page.
For cases when a cfcatch block is not able to successfully handle an error, consider using the cfrethrow tag, as
described in Using the cfrethrow tag on page 296.
If an exception can be safely ignored, use a cfcatch tag with no body; for example:
<cfcatch Type = Database />
In problematic cases, enclose an exception-prone tag in a specialized combination of cftry and cfcatch tags to
immediately isolate the tag's exceptions.
Exception information in cfcatch blocks
Within the body of a cfcatch tag, the active exceptions properties are available in a cfcatch object. The object
contents are described as follows:
Standard cfcatch variables
The following table describes the variables that are available in most cfcatch blocks:
290
Property variable
Description
cfcatch.Detail
A detailed message from the CFML compiler. This message, which can contain HTML formatting, can help
to determine which tag threw the exception.
The cfcatch.Detail value is available in the CFScript catch statement as the exceptionVariable
parameter.
cfcatch.ErrorCode
The cfthrow tag can supply a value for this code through the errorCode attribute. For
Type="Database", cfcatch.ErrorCode has the same value as cfcatch.SQLState.
Otherwise, the value of cfcatch.ErrorCode is the empty string.
cfcatch.ExtendedInfo
Custom error message information. This is returned only to cfcatch tags for which the type attribute is
Application or a custom type.
Otherwise, the value of cfcatch.ExtendedInfo is the empty string.
cfcatch.Message
The exceptions default diagnostic message, if one was provided. If no diagnostic message is available, this
is an empty string.
The cfcatch.Message value is included in the value of the CFScript catch statement
exceptionVariable parameter.
cfcatch.RootCause
The Java servlet exception reported by the JVM as the cause of the root cause of the exception.
cfcatch.TagContext
An array of structures structure containing information for each tag in the tag stack The tag stack consists
of each tag that is currently open.
cfcatch.Type
Note: If you use the cfdump tag to display the cfcatch variable, the display does not include variables that do not have
values.
The cfcatch.TagContext variable contains an array of tag information structures. Each structure represents one
level of the active tag context at the time when ColdFusion detected the exception. That is, there is one structure for
each tag that is open at the time of the exception. For example, if the exception occurs in a tag on a custom tag page,
the tag context displays information about the called custom tag and the tag in which the error occurs.
The structure at position 1 in the array represents the currently executing tag at the time the exception was detected.
The structure at position ArrayLen represents the initial tag in the stack of tags that were executing when the compiler
detected the exception.
The following table lists the tagContext structure attributes:
Entry
Description
Column
ID
The tag in which the exception occurred. Exceptions in CFScript are indicated by two
question marks (??). All custom tags, including those called directly, are identified as
cfmodule.
Line
Raw_Trace
Template
Type
Database exceptions
The following additional variables are available whenever the exception type is database:
291
Property variable
Description
cfcatch.NativeErrorCode
The native error code associated with this exception. Database drivers typically provide
error codes to assist in the diagnosis of failing database operations. The values assumed by
cfcatch.NativeErrorCode are driver-dependent.
If no error code is provided, the value of cfcatch.nativeErrorCode is -1. The value is 0
for queries of queries.
cfcatch.SQLState
The SQLState code associated with this exception. Database drivers typically provide error
codes to assist in the diagnosis of failing database operations. SQLState codes are more
consistent across database systems than native error codes.
If the driver does not provide an SQLState value, the value of cfcatch.SQLState is -1.
cfcatch.Sql
cfcatch.queryError
cfcatch.where
If the query uses the cfqueryparam tag, query parameter name-value pairs.
Expression exceptions
The following variable is only available for Expression exceptions:
Property variable
Description
cfcatch.ErrNumber
Locking exceptions
The following additional information is available for exceptions related to errors that occur in cflock tags:
Property variable
Description
cfcatch.lockName
The name of the affected lock. This is set to "anonymous" if the lock name is unknown.
cfcatch.lockOperation
The operation that failed. This is set to "unknown" if the failed operation is unknown.
Description
cfcatch.missingFileName
292
293
</cfoutput>
<cfset errorCaught = "Database">
</cfcatch>
<!--- Use cfcatch with type="Any" --->
<!--- to find unexpected exceptions. --->
<cfcatch type="Any">
<cfoutput>
<hr>
<h1>Other Error: #cfcatch.Type#</h1>
<ul>
<li><b>Message:</b> #cfcatch.Message#
<li><b>Detail:</b> #cfcatch.Detail#
</ul>
</cfoutput>
<cfset errorCaught = "General Exception">
</cfcatch>
</body>
</html>
</cftry>
to:
FROM Employer
Display the page. This time the cfcatch type="Database" block displays an error message.
4 Change Employer to Employee.
to:
<p>Department: #DepartmentID#<br>
Display the page. This time the cfcatch type="Any" block displays an error message indicating an expression
error.
5 Change DepartmentID back to Dept_ID and redisplay the page. The page displays properly.
Open \CFusion\Log\MyAppPage.log in your text editor. You should see a header line, an initialization line, and
four detail lines, like the following:
294
"Severity","ThreadID","Date","Time","Application","Message"
"Information","web-0","11/20/01", "16:27:08",, "cf_root\runtime\servers\default\logs\
MyAppPage.log initialized"
"Information","web-0","11/20/01","16:27:08",,
"Page: web_root/MYStuff/MyDocs/ cftryexample.cfm Error: MissingInclude"
"Information","web-1","11/20/01","16:27:32",,"
Page: web_root/MYStuff/MyDocs/ cftryexample.cfm Error: "
"Information","web-0","11/20/01","16:27:49",,
"Page: web_root/MYStuff/MyDocs/ cftryexample.cfm Error: Database"
"Information","web-1","11/20/01","16:28:21",,
"Page: web_root/MYStuff/MyDocs/ cftryexample.cfm Error: General Exception"
"Information","web-0","11/20/01","16:28:49",,
"Page: web_root/MYStuff/MyDocs/ cftryexample.cfm Error: "
Description
<cfset EmpID=3>
<cfparam name="errorCaught" default="">
<cftry>
<cfquery name="test"
datasource="cfdocexamples">
SELECT Dept_ID, FirstName, LastName
FROM Employee
WHERE Emp_ID=#EmpID#
</cfquery>
Starts the cftry block. Exceptions from here to the end of the block can be
caught by cfcatch tags.
<html>
<head>
<title>Test cftry/cfcatch</title>
</head>
<body>
<cfinclude template="includeme.cfm">
<cfoutput query="test">
<p>Department: #Dept_ID#<br>
Last Name: #LastName#<br>
First Name: #FirstName#</p>
</cfoutput>
Begins the HTML page. This section contains all the code that displays
information if no errors occur.
<cfcatch type="MissingInclude">
<h1>Missing Include File</h1>
<cfoutput>
<ul>
<li><b>Message:</b> #cfcatch.Message#
<li><b>Detail:</b> #cfcatch.Detail#
<li><b>Filename:</b> #cfcatch.MissingFileName#
</ul>
</cfoutput>
<cfset errorCaught = "MissingInclude">
</cfcatch>
Queries the cfdocexamples database to get the data for the employee
identified by the EmpID variable.
295
Code
Description
<cfcatch type="Database">
<h1>Database Error</h1>
<cfoutput>
<ul>
<li><b>Message:</b> #cfcatch.Message#
<li><b>Native error code:</b>
#cfcatch.NativeErrorCode#
<li><b>SQLState:</b> #cfcatch.SQLState#
<li><b>Detail:</b> #cfcatch.Detail#
</ul>
</cfoutput>
<cfset errorCaught = "Database">
</cfcatch>
<cfcatch type="Any">
<cfoutput>
<hr>
<h1>Other Error: #cfcatch.Type#</h1>
<ul>
<li><b>Message:</b> #cfcatch.Message#
<li><b>Detail:</b> #cfcatch.Detail#
</ul>
</cfoutput>
<cfset errorCaught = "General Exception">
</cfcatch>
</body>
</html>
</cftry>
Since the error can occur after information has displayed (in this case, the
contents of the include file), draws a line before writing the message text.
Displays the ColdFusion basic and detailed error message.
Sets the errorCaught variable to indicate the error type.
Meaning
type
The type of error. It can be a custom type that has meaning only to your application, such as InvalidProductCode.
You can also specify Application, the default type. You cannot use any of the predefined ColdFusion error types,
such as Database or MissingTemplate.
message
detail
errorCode
An error code that is meaningful to the application. This field is useful if the application uses numeric error codes.
extendedInfo
All of these values are optional. You access the attribute values in cfcatch blocks and Exception type error pages by
prefixing the attribute with either cfcatch or error, as in cfcatch.extendedInfo. The default ColdFusion error
handler displays the message and detail values in the Message pane and the remaining values in the Error Diagnostic
Information pane.
Catching and displaying thrown errors
The cfcatch tag catches a custom exception when you use any of the following values for the cfcatchtype attribute:
Application, which matches an exception that is thrown with the Applicationtype attribute or with no type
attribute.
296
Any, which matches any exception that is not caught by a more specific cfcatch tag.
Similarly, if you specify any of these types in a cferror tag, the specified error page displays information about the
thrown error.
Because the cfthrow tag generates an exception, a Request error handler or the Site-wide error handler can also
display these errors.
Custom error type name hierarchy
You can name custom exception types using a method that is similar to Java class naming conventions: domain name
in reverse order, followed by project identifiers, as in the following example:
<cfthrow
type="com.myCompany.myApp.Invalid_field.codeValue"
errorcode="Dodge14B">
This fully qualified naming method is not required; you can use shorter naming rules, for example,
myApp.Invalid_field.codeValue, or even codeValue.
This naming method is not just a convention; ColdFusion uses the naming hierarchy to select from a possible
hierarchy of error handlers. For example, assume that you use the following cfthrow statement:
<cfthrow type="MyApp.BusinessRuleException.InvalidAccount">
Any of the following cfcatch error handlers would handle this error:
<cfcatch type="MyApp.BusinessRuleException.InvalidAccount">
<cfcatch type="MyApp.BusinessRuleException">
<cfcatch type="MyApp">
The handler that most exactly matches handles the error. In this case, the
MyApp.BusinessRuleException.InvalidAccount handler runs. However, if you used the following cfthrow tag:
<cfthrow type="MyApp.BusinessRuleException.InvalidVendorCode
297
<cftry>
<cftry>
Code that might throw a database error
<cfcatch Type="Database">
<cfif Error is of type I can Handle>
Handle it
<cfelse>
<cfrethrow>
</cfif
</cfcatch>
</cftry>
<cfcatch Type="Any">
General Error Handling code
</cfcatch>
</cftry>
Although this example uses a Database error as an example, you can use any cfcatch type attribute in the innermost
error type.
Follow these rules when you use the cfrethrow tag:
Nest cftry tags, with one tag for each level of error handling hierarchy. Each level contains the cfcatch tags for
that level of error granularity.
Place the most general error catching code in the outermost cftry block.
Place the most specific error catching code in the innermost cftry block.
Place the code that can cause an exception error at the top of the innermost cftry block.
End each cfcatch block except those in the outermost cftry block with a cfrethrow tag.
The calling page does little more than call the custom tag with a single attribute, a name to be looked up in a
database. It does show, however, how a calling page can handle an exception thrown by the custom tag.
The custom tag finds all records in the cfdocexamples database with a matching last name, and returns the results
in a Caller variable. If it fails to connect with the main database, it tries a backup database.
The calling page
The calling page represents a section from a larger application page. To keep things simple, the example hard-codes
the name to be looked up.
<cftry>
<cf_getEmps EmpName="Jones">
<cfcatch type="myApp.getUser.noEmpName">
<h2>Oops</h2>
<cfoutput>#cfcatch.Message#</cfoutput><br>
</cfcatch>
</cftry>
<cfif isdefined("getEmpsResult")>
<cfdump var="#getEmpsResult#">
</cfif>
298
Description
<cftry>
<cf_getEmps EmpName="Jones">
<cfcatch type="myApp.getUser.noEmpName">
<h2>Oops</h2>
<cfoutput>#cfcatch.Message#</cfoutput><br>
</cfcatch>
<cfif isdefined("getEmpsResult")>
<cfdump var="#getEmpsResult#">
</cfif>
If the tag returns a result, uses the cfdump tag to display it. (A
production application would not use the cfdump tag.)
299
300
Code
Description
<cfelse>
<cftry>
<cftry>
<!--- Try to query the main database and set a caller
variable to the result --->
<cfquery Name = "getUser" DataSource="cfdocexamples">
SELECT *
FROM Employee
WHERE LastName = '#attributes.EmpName#'
</cfquery>
<cfset caller.getEmpsResult = getuser>
If the query threw a Database error, checks to see if the error was
caused by an inability to access the database (indicated by an
SQLState variable value of S100 or IM002).
If the second database query failed for any other reason, throws
the error up to the next try block.
<cfelse>
<cfrethrow>
</cfif>
</cfcatch>
In the second try block, handles the case in which the first
database query failed for a reason other than a failure to find the
database.
If the database was not found, starts a third nested try block and
tries accessing the backup database. This try block catches
exceptions in this second database access.
If the database inquiry succeeds, sets the calling pages
getEmpsResult variable with the query results.
Rethrows the error up to the next level, the outermost try block.
<cfcatch type = "Any">
<cfrethrow>
</cfcatch>
</cftry>
In the second try block, catches any errors other exceptions and
rethrows them up to the outermost try block.
301
In the calling page, change the attribute name to any other value; for example, My Attrib. Then change it back.
In the first cfquery tag, change the data source name to an invalid data source; for example, NoDatabase.
With an invalid first data source name, change the data source in the second cfquery tag to cfdocexamples.
Insert cfthrow tags throwing custom exculpations in various places in the code and observe the effects.
302
Variable scope
Description
Client
Contains variables that are available for a single client browser over multiple browser sessions in an application.
For information about browser sessions, see, What is a session? on page 311.
Useful for client-specific information, such as client preferences, that you want to store for a significant period of
time.
Data is stored as cookies, database entries, or Registry values. Client variables can time out after an extended
period.
Although do not have to use the Client scope prefix in the variable name, code that uses the prefix is more
efficient and easier to maintain.
Session
Contains variables that are available for a single client browser for a single browser session in an application.
Useful for client-specific information, such as shopping cart contents, that you want to persist while the client is
visiting your application.
Data is stored in memory and times out after a period of inactivity or when the server shuts down.
ColdFusion Administrator lets you select between two kinds of session management, Standard ColdFusion
Session management and J2EE session management. For information about types of session management, see
ColdFusion and J2EE session management on page 312.
Use the Session scope prefix in the variable name.
Application
Contains variables that are available to all pages in an application for all clients.
Useful for application-specific information, such as contact information, that can vary over time and should be
stored in a variable.
Data is stored in memory and times out after a period of inactivity or when the server shuts down.
Use the Application scope prefix in the variable name.
Server
Contains variables that are available to all applications in a server and all clients.
Useful for information that applies to all pages on the server, such as an aggregate page-hit counter.
Data is stored in memory. The variables do not time out, but you can delete variables you create, and all server
variables are automatically deleted when the server stops running.
Use the Server scope prefix in the variable name.
The following sections provide information that is common to all or several of these variables. Later sections describe
how to use the Client, Session, Application, and Server scopes in your applications, and provide detailed information
about locking code.
303
All variables in these scopes are lost if the server stops running.
Variables in these scopes are not shared by servers in a cluster.
To prevent race conditions and ensure data consistency, lock access to all code that changes variables in these
scopes or reads variables in these scopes with values that can change.
Note: If you use J2EE session management and configure the J2EE server to retain session data between server restarts,
ColdFusion retains session variables between server restarts.
Additionally, be careful when using client variables in a server cluster, where an application can run on multiple
servers.
Locking memory variables
Because ColdFusion is a multi-threaded system in which multiple requests can share Session, Application, and Server
scope variables, it is possible for two or more requests to try to access and modify data at the same time. ColdFusion
runs in a J2EE environment, which prevents simultaneous data access, so multiple requests do not cause severe system
errors. However, such requests can result in inconsistent data values, particularly when a page changes more than one
variable.
To prevent data errors with session, application, and server variables, lock code that writes and reads data in these
scopes. For more information, see Locking code with cflock on page 318.
Using variables in clustered systems
Because memory variables are stored in memory, they are not available to all servers in a cluster. As a result, you
generally do not use Session, Application, or Server scope variables in clustered environment. However, use these
scope variables in a clustered system in the following circumstances:
If the clustering system supports sticky sessions, in which the clustering system ensures that each user session
remains on a single server. In this case, you can use session variables as you would on a single server.
You can use Application and Server scope variables in a cluster for write-once variables that are consistently set, for
example, from a database.
To use client variables on a clustered system, store the variables as cookies or in a database that is available to all servers.
If you use database storage, on one server only, select the Purge Data for Clients that Remain Unvisited option on the
Client Variables, Add/Edit Client Store page in the Server Settings area in the ColdFusion Administrator.
304
Description
Client
Data is saved as cookies, database entries, or Registry entries. Data is saved between server restarts, but is initially
accessed and saved more slowly than data stored in memory.
Each type of data storage has its own time-out period. You can specify the database and Registry data time-outs
in the ColdFusion Administrator. ColdFusion sets Cookie client variables to expire after approximately ten years.
Data is stored on a per-user and per-application basis. For example, if you store client variables as cookies, the user
has a separate cookie for each ColdFusion application provided by a server.
Client variables must be simple variables, such as numbers, dates, or strings. They cannot be arrays, structures,
query objects, or other objects.
Client variable names can include periods. For example, My.ClientVar is a valid name for a simple client variable.
Avoid such names, however, to ensure code clarity.
You do not have to prefix client variables with the scope name when you reference them, However, if you do not
use the Client prefix, you might unintentionally refer to a variable with the same name in another scope. Using
the prefix also optimizes performance and increases program clarity.
You do not lock code that uses client variables.
You can use client variables that are stored in cookies or a common database in clustered systems.
Session
Session variables are normally better than client variables for values that need to exist for only a single browser session.
Reserve client variables for client-specific data, such as client preferences that you want available for multiple browser
sessions.
305
These cookies uniquely identify the client to ColdFusion, which also maintains copies of the variables as part of the
Session and Client scopes. You can configure your application so that it does not use client cookies, but in this case,
pass these variables to all the pages that your application calls. For more information about maintaining client and
session information without using cookies, see Using client and session variables without cookies on page 305.
You can configure ColdFusion to use J2EE servlet session management instead of ColdFusion session management
for session variables. This method of session management does not use CFID and CFToken values, but does use a clientside jsessionid session management cookie. For more information on using J2EE session management, see
ColdFusion and J2EE session management on page 312.
Using client and session variables without cookies
Often, users disable cookies in their browsers. In this case, ColdFusion cannot maintain the client state automatically.
You can use client or session variables without using cookies, by passing the client identification information between
application pages. However, this technique has significant limitations, as follows:
1 Client variables are effectively the same as session variables, except that they leave unusable data in the client data
store.
Because the clients system does not retain any identification information, the next time the user logs on,
ColdFusion cannot identify the user with the previous client and must create a new client ID for the user. Any
information about the user from a previous session is not available, but remains in client data storage until
ColdFusion deletes it. If you clear the Purge Data for Clients that Remain Unvisited option in the ColdFusion
Administrator, ColdFusion never deletes this data.
Therefore, do not use client variables, if you allow users to disable cookies. To retain client information without
cookies, require users to login with a unique ID. You can then save user-specific information in a database with the
users ID as a key.
2 ColdFusion creates a new session each time the user requests a page directly in the browser, because the new request
If the client does not accept cookies, automatically appends all required client identification information to a URL.
If the client accepts cookies, does not append the information.
The URLSessionFormat function automatically determines which identifiers are required, and sends only the
required information. It also provides a more secure and robust method for supporting client identification than
manually encoding the information in each URL, because it only sends the information that is required, when it is
required, and it is easier to code.
306
To use the URLSessionFormat function, enclose the request URL in the function. For example, the following cfform
tag posts a request to another page and sends the client identification, if necessary:
<cfform method="Post" action="#URLSessionFormat("MyActionPage.cfm")#>
If you use the same page URL in multiple URLSessionFormat functions, you can gain a small performance
improvement and simplify your code if you assign the formatted page URL to a variable, for example:
<cfset myEncodedURL=URLSessionFormat(MyActionPage.cfm)>
<cfform method="Post" action="#myEncodedURL#">
CFID, CFTOKEN, and jsessionid are marked httpOnly. This reduces the chance of session information being
compromised on Cross Site Scripting (XSS) attack.
Set the following system property for the session cookies to be httpOnly:
Dcoldfusion.sessioncookie.httponly=true
307
The support for session cookies to be httpOnly depends on the application server you use:
For Tomcat/JBoss, httpOnly is not supported for JSESSIONID
On JRun, add the system property, Dcoldfusion.sessioncookie.httponly=true , in the jvm.config file
For other application servers, see the relevant documentation for details on httpOnly support for session
cookies.
Registry (default). Client variables are stored under the key HKEY_LOCAL_MACHINE\
SOFTWARE\Macromedia\ColdFusion\CurrentVersion\Clients.
Cookie
Generally, it is most efficient to store client variables in a database. Although the Registry option is the default, the
Registry has significant limitations for client data storage. The Registry cannot be used in clustered systems and its use
for client variables on UNIX is not supported in ColdFusion.
Using cookie storage
When you set the client storage method to Cookie, the cookie that ColdFusion creates has the applications name.
Storing client data in a cookie is scalable to large numbers of clients, but this storage mechanism has some limitations.
In particular, if the client turns off cookies in the browser, client variables do not work.
Consider the following additional limitations before implementing cookie storage for client variables:
Any Client variable that you set after a cfflush tag is not sent to the browser, so the variable value does not get
saved.
Some browsers allow only 20 cookies to be set from a particular host. ColdFusion uses two of these cookies for the
CFID and CFToken identifiers, and also creates a cookie named cfglobals to hold global data about the client, such
as HitCount, TimeCreated, and LastVisit. This limits you to 17 unique applications per client-host pair.
308
Some browsers set a size limit of 4K bytes per cookie. ColdFusion encodes nonalphanumeric data in cookies with
a URL encoding scheme that expands at a 3-1 ratio, which means you should not store large amounts of data per
client. ColdFusion throws an error if you try to store more than 4,000 encoded bytes of data for a client.
Configuring database storage
When you specify a database for client variable storage, do not always have to manually create the data tables that store
the client variables.
If ColdFusion can identify that the database you are using supports SQL creation of database tables, create the database
in advance. When you click the Add button on the Select Data Source to Add as Client Store box on the Memory
Variables page, the Administrator displays a Add/Edit Client Store page which contains a Create Client Database
Tables selection box. Select this option to have ColdFusion create the necessary tables in your database. (The option
does not appear if the database already has the required tables.)
If your database does not support SQL creation of tables, or if you are using the ODBC socket [Macromedia] driver to
access your database, use your database tool to create the client variable tables. Create the CDATA and CGLOBAL
tables.
The CDATA table must have the following columns:
Column
Data type
cfid
CHAR(64), TEXT, VARCHAR, or any data type capable of taking variable length strings up to 64 characters
app
CHAR(64), TEXT, VARCHAR, or any data type capable of taking variable length strings up to 64 characters
data
MEMO, LONGTEXT, LONG VARCHAR, CLOB, or any data type capable of taking long, indeterminate-length strings
Data type
cfid
CHAR(64), TEXT, VARCHAR, or any data type capable of taking variable length strings up to 64 characters
data
MEMO, LONGTEXT, LONG VARCHAR, CLOB, or any data type capable of taking long, indeterminate-length strings
lvisit
TIMESTAMP, DATETIME, DATE, or any data type that stores date and time values
Note: Different databases use different names for their data types. The names in the preceding tables are common, but
your database might use other names.
To improve performance, create indexes when you create these tables. For the CDATA table, index these cfid and app
columns. For the CGLOBAL table, index the cfid column.
Specifying client variable storage in your application
The override the default client variable storage location, set the This.clientstorage variable in the Application.cfc
initialization code, or use the cfapplication tag clientStorage attribute.
The following lines from an Application.cfc file tell ColdFusion to store the client variables in the mydatasource data
source:
<cfscript>
This.name"SearchApp";
This.clientManagement="Yes";
This.clientStorage="mydatasource";
</cfscript>
309
The following code from an Application.cfm file does the same thing as the previous example:
<cfapplication name"SearchApp"
clientmanagement="Yes"
clientstorage="mydatasource">
After you set a client variable this way, it is available for use within any page in your application that is accessed by the
client for whom the variable is set.
The following example shows how to use the cfparam tag to check for the existence of a client parameter and set a
default value if the parameter does not exist:
<cfparam name="Client.FavoriteColor" default="Red">
To change the clients favorite color, for example, use code such as the following:
<cfset Client.FavoriteColor = Form.FavoriteColor>
310
Variable
Description
Client.CFID
Client.CFToken
The client security token, normally stored on the client system as a cookie.
Client.URLToken
Client.HitCount
Client.LastVisit
Client.TimeCreated
The time the CFID and CFToken variables that identify the client to ColdFusion were first created.
Note: ColdFusion lets you delete or change the values of the built-in client variables. As a general rule, avoid doing so.
You use the Client.CFID, Client.CFToken, and Client.URLToken variables if your application supports browsers
that do not allow cookies. For more information on supporting browsers that do not allow cookies, see Using client
and session variables without cookies on page 305.
You can use the Client.HitCount and time information variables to customize behavior that depends on how often
users visit your site and when they last visited. For example, the following code shows the date of a user's last visit to
your site:
<cfoutput>
Welcome back to the Web SuperShop. Your last
visit was on #DateFormat(Client.LastVisit)#.
</cfoutput>
The GetClientVariablesList function returns a comma-separated list of the names of the client variables for the
current application. The standard system-provided client variables (CFID, CFToken, URLToken, HitCount,
TimeCreated, and LastVisit) are not returned in the list.
Deleting client variables
To delete a client variable, use the StructDelete function or the DeleteClientVariable function. For example, the
following lines are equivalent:
<cfset IsDeleteSuccessful=DeleteClientVariable("MyClientVariable")>
<cfset IsDeleteSuccessful=StructDelete(Client, "MyClientVariable")>
The Client Variables page in the ColdFusion Administrator lets you set a time-out period of inactivity after which
ColdFusion removes client variables stored in either the Registry or a data source. (The default value is 10 days for
client variables stored in the Registry, and 90 days for client variables stored in a data source.)
Note: You cannot delete the system-provided client variables (CFID, CFToken, URLToken, HitCount, TimeCreated, and
LastVisit).
311
After you create a Registry file, you can copy it to a new machine and import it by clicking Import Registry File on the
Registry editor Registry menu.
Note: On UNIX systems, the registry entries are kept in /opt/coldfusion/registry/cf.registry, a text file that you can copy
and edit directly.
What is a session?
A session refers to all the connections that a single client makes to a server in the course of viewing any pages associated
with a given application. Sessions are specific to both the individual user and the application. As a result, every user of
an application has a separate session and has access to a separate set of session variables.
This logical view of a session begins with the first connection to an application by a client and ends after that client's
last connection. However, because of the stateless nature of the web, it is not always possible to define a precise point
at which a session ends. A session should end when the user finishes using an application. In most cases, however, a
web application has no way of knowing if a user has finished or is just lingering over a page.
312
Therefore, sessions always terminate after a time-out period of inactivity. If the user does not access a page of the
application within this time-out period, ColdFusion interprets this as the end of the session and clears any variables
associated with that session.
The default time-out for session variables is 20 mins. You can change the default time-out on the Memory Variables
page in the Server Settings area in the ColdFusion Administrator.
You can also set the time-out period for session variables inside a specific application (thereby overruling the
Administrator default setting) by setting the Application.cfc This.sessionTimeout variable or by using the
cfapplication tag sessionTimeout attribute. However, you cannot set a time-out value for that is greater than the
maximum session time-out value set on the Administrator Memory Variables page.
For detailed information on ending sessions and deleting session variables, see Ending a session on page 315.
ColdFusion and J2EE session management
The ColdFusion server can use either of the following types of session management:
J2EE session management uses a session-specific session identifier, jsessionid, which is created afresh at the start
of each session.
You can share session variables between ColdFusion pages and JSP pages or Java servlets that you call from the
ColdFusion pages.
The Session scope is serializable (convertible into a sequence of bytes that can later be fully restored into the original
object). With ColdFusion session management, the Session scope is not serializable. Only serializable scopes can be
shared across servers.
Therefore, consider using J2EE session management in any of the following cases:
You want to maximize session security, particularly if you also use client variables
You want to share session variables between ColdFusion pages and JSP pages or servlets in a single application.
You want to be able to manually terminate a session while maintaining the client identification cookie for use by
the Client scope.
You want to support clustered sessions; for example, to support session failover among servers.
ColdFusion Administrator
The Application.cfc initialization code This.sessionManagement variable or the active cfapplication tag.
ColdFusion Administrator, Application.cfc, and the cfapplication tag also provide facilities for configuring session
variable behavior, including the variable time-out.
313
Select to use ColdFusion session management (the default) or J2EE session management.
Change the default session time-out. Application code can override this value. The default value for this time-out
is 20 mins.
Specify a maximum session time-out. Application code cannot set a time-out greater than this value. The default
value for this time-out is two days.
Enabling session variables in your application
Enable session variables in the initialization code of your Application.cfc file or in the cfapplication tag in your
Application.cfm file.
Do the following in the Application.cfc initialization code, below the cfcomponent tag, to enable session variables:
Set This.sessionManagement="Yes".
Set This.name to specify the name of the application.
Optionally, set This.sessionTimeout to set an application-specific session time-out value. Use the CreateTimeSpan
function to specify the number of days, hours, minutes, and seconds for the time-out.
Do the following in the Application.cfm file to enable session variables:
Set sessionManagement="Yes"
Use the name attribute to specify the name of the application.
Optionally, use the sessionTimeout attribute to set an application-specific session time-out value. Use the
CreateTimeSpan function to specify the number of days, hours, minutes, and seconds for the time-out.
The following sample code enables session management for the GetLeadApp application and sets the session variables
to time out after a 45-minute period of inactivity:
<cfapplication name="GetLeadApp"
sessionmanagement="Yes"
sessiontimeout=#CreateTimeSpan(0,0,45,0)#>
314
Variable
Description
Session.CFID
ColdFusion session management only: the client ID, normally stored on the client system as a cookie.
Session.CFToken
ColdFusion session management only: the client security token, normally stored on the client system as a
cookie.
Session.URLToken
ColdFusion session management: A combination of the CFID and CFToken values in the form
CFID=IDNum&CFTOKEN=tokenNum. Use this variable if the client does not support cookies and you must
pass the CFID and CFToken variables from page to page.
J2EE session management: A combination of the CFID and CFToken cookies and the J2EE session ID, in
the form CFID=IDNum&CFTOKEN=tokenNum&jsessionid=SessionID.
Session.SessionID
Note: ColdFusion lets you delete or change the values of the built-in session variables. As a general rule, avoid doing so.
If you enable client variables and ColdFusion session management, ColdFusion uses the same values for the Client and
Session scope CFID, CFToken, and URLtoken variables. ColdFusion gets the values for these variables from the same
source, the clients CFID and CFTOKEN cookies.
If you use J2EE session management, the Session scope does not include the Session.CFID or Session.CFToken
variables, but does include the Session.URLToken and Session.SessionID variables. In this case, the
Session.SessionID is the J2EE session ID and Session.URLToken consists of the string jsessionid= followed by
the J2EE session ID.
Important: Always put code that accesses session variables inside cflock tags.
Note: If you set session variables on a CFML template that uses the cflocation tag, ColdFusion might not set the
variables. For more information, see TechNote at www.adobe.com/go/tn_18171.
315
For example, to display the number of items in a users shopping cart, use the following code:
<cflock timeout=20 scope="Session" type="Exclusive">
<cfoutput>
Your shopping cart has #Session.ShoppingCartItems# items.
</cfoutput>
</cflock>
To increase the number of items in the shopping cart, use the following code:
<cflock timeout=20 scope="Session" type="Exclusive">
<cfset Session.ShoppingCartItems = Session.ShoppingCartItems + 1>
</cflock>
Ending a session
The following rules apply to ending a session and deleting Session scope variables:
If you use ColdFusion session management, ColdFusion automatically ends sessions and deletes all Session scope
variables if the client is inactive for the session time-out period. The session does not end when the user closes the
browser.
If you use J2EE session management, ColdFusion ends the session and deletes all Session scope variables if the client
is inactive for the session time-out period. However, the browser continues to send the same session ID, and
ColdFusion reuses this ID for sessions with this browser instance, as long as the browser remains active.
Logging a user out does not end the session or delete Session scope variables.
In many cases, you can effectively end a session by clearing the Session scope, as shown in the following line. The
following list, however, includes important limitations and alternatives:
<cfset StructClear(Session)>
Clearing the Session scope does not clear the session ID, and future requests from the browser continue to use the
same session ID until the browser exits. It also does not log out the user, even if you use Session scope storage for
login information. Always use the cflogout tag to log out users.
If you use J2EE session management, you can invalidate the session, as follows:
<cfset getPageContext().getSession().invalidate()>
This line creates a pointer to the servlet page context and calls an internal method to reset the session. This clears
all session information, including the session ID Session scope variables, and if you are using session login storage,
the login information, for future request. However, the session information does remain available until the end of
the current request. After you invalidate a session, attempts by the browser to access the application will generate
an invalid session exception until the session times out.
Note: You cannot destroy the session and create a session on the same request, as creating a new session involves
sending session cookies back.
If you do not use client cookies, the Session scope and login state is available to your application only as long as you
pass the sessions CFID, CFTOKEN, and, for J2EE sessions, jsessionid values in the URL query string. After you
stop using these values, however, the session data remains in memory until the session time-out period elapses.
316
You set the application name in the cfapplication tag, normally on your applications Application.cfm page. The
application name is stored in the Application.applicationName variable.
Unlike client and session variables, application variables do not require that a client name (client ID) be associated with
them. They are available to any clients that use pages in the application.
Important: Place code that uses application variables inside cflock tags in circumstances that could result in race
conditions from multiple accesses to the same variable. For information on using cflock tags, see Locking code with
cflock on page 318.
Ensure that they are enabled in the ColdFusion Administrator. (They are enabled by default.)
Specify the application name by setting the This.name variable in the initialization code of the Application.cfc or
by setting the name attribute of the cfapplication tag for the current page.
Note: ColdFusion supports unnamed applications for compatibility with J2EE applications. For more information, see
Unnamed ColdFusion Application and Session scopes on page 1131
The ColdFusion Administrator also lets you specify the following information:
A default variable time-out. If all pages in an application are inactive for the time-out period, ColdFusion deletes
all the application variables. The Application.cfc file or cfapplication tag can override this value for a specific
application. The default value for this time-out is two days.
A maximum time-out. The application code cannot set a time-out greater than this value. The default value for this
time-out is two days.
You can set the time-out period for application variables within a specific application by using the
This.applicationTimeout variable of Application.cfc or the applicationTimeout attribute of the cfapplication tag.
317
Because each Application scope variable is shared in memory by all requests in the application, these variables can
become bottlenecks if used inappropriately. Whenever a request is reading or writing an Application scope variable,
any other requests that use the variable must wait until the code accessing the variable completes. This problem is
increased by the processing time required for locking. If many users access the application simultaneously and you use
Application scope variables extensively, your application performance might degrade. If your application uses many
application variables, consider whether the variables must be in the Application scope or whether they can be Session
or Request scope variables.
The application scope has one built-in variable, Application.applicationName, which contains the application
name you specify in the cfapplication tag.
Access and manipulate application variables the same way you use session variables, except that you use the variable
prefix Application, not Session, and specify Session as the lock scope. For examples of using session variables see
Creating and deleting session variables on page 314 and Accessing and changing session variables on page 314.
For information on locking write-once read-many application variables efficiently, see Locking application variables
efficiently on page 323
Description
Server.ColdFusion.AppServer
The name of the J2EE application server ColdFusion is using. For ColdFusion server
editions, which have an integrated application server, the name is JRun4.
Server.ColdFusion.Expiration
The date on which the ColdFusion license expires if it is the trial version.
Server.ColdFusion.ProductLevel
Server.ColdFusion.ProductName
Server.ColdFusion.ProductVersion
The version number for the server that is running, such as 6,0,0.
Server.ColdFusion.Rootdir
Server.ColdFusion.SerialNumber
Server.ColdFusion.SupportedLocales
The locales, such as English (US) and Spanish (Standard), supported by the server.
Server.OS.AdditionalInformation
Additional information provided by the operating system, such as the Service Pack
number.
Server.OS.arch
318
Variable
Description
Server.OS.BuildNumber
Server.OS.Name
Server.OS.Version
Protect sections of code that access and manipulate shared data in the Session, Application, and Server scopes, and
in the Request and Variables scopes for applications that use ColdFusion threads.
Ensure that file updates do not fail because files are open for writing by other applications or ColdFusion tags.
Ensure that applications do not try to simultaneously access ColdFusion extension tags written using the CFX API
that are not thread-safe. This is important for CFX tags that use shared (global) data structures without protecting
them from simultaneous access (not thread-safe). However, Java CFX tags can also access shared resources that
could become inconsistent if the CFX tag access is not locked.
Ensure that applications do not try to simultaneously access databases that are not thread-safe. (This is not
necessary for most database systems.)
ColdFusion is a multi-threaded web application server that can process multiple page requests at a time. As a result,
the server can attempt to access the same information or resources simultaneously, as the result of two or more
requests.
Although ColdFusion is thread-safe and does not try to modify a variable simultaneously, it does not ensure the correct
order of access to information. If multiple pages, or multiple invocations of a page, attempt to write data
simultaneously, or read and write it at the same time, the resulting data can be inconsistent, as shown in the following
Sample locking scenarios section.
Similarly, ColdFusion cannot automatically ensure that two sections of code do not attempt to access external
resources such as files, databases, or CFX tags that cannot properly handle simultaneous requests. Nor can ColdFusion
ensure that the order of access to these shared resources is consistent and results in valid data.
By locking code that accesses such resources so that only one thread can access the resource at a time, you can prevent
race conditions.
319
Suppose that ColdFusion processes two ticket orders at approximately the same time, and that the value of
Application.totalTicketsSold is initially 160. The following sequence might happen:
1 Order 1 reads the total tickets sold as 160.
2 Order 2 reads the total tickets sold as 160.
3 Order 1 adds an order of 5 tickets to 160 to get 165.
4 Order 2 adds an order of 3 tickets to 160 to get 163.
5 Order 1 saves the value 165 to Application.totalTicketsSold
6 Order 2 saves the value 163 to Application.totalTicketsSold
The application now has an inaccurate count of the tickets sold, and is in danger of selling more tickets than the
auditorium can hold.
To prevent this from happening, lock the code that increments the counter, as follows:
<cflock scope="Application" timeout="10" type="Exclusive">
<cfset Application.totalTicketsSold = Application.totalTicketsSold + ticketOrder>
</cflock>
The cflock tag ensures that while ColdFusion performs the processing in the tag body, no other threads can access
the Application scope. As a result, the second transaction is not processed until the first one completes. The processing
sequence looks something like the following:
1 Order 1 reaches the lock tag, which gets an Application scope lock.
2 Order 1 reads the total tickets sold as 160.
3 Order 2 reaches the lock tag. Because there is an active Application scope lock, ColdFusion waits for the lock to free.
4 Order 1 adds an order of 5 tickets to 160 to get 165.
5 Order 1 saves the value 165 to Application.totalTicketsSold.
6 Order 1 exits the lock tag. The Application scope lock is now free.
7 Order 2 gets the Application scope lock and can begin processing.
8 Order 2 reads the total tickets sold as 165.
9 Order 2 adds an order of 3 tickets to 165 to get 168.
10 Order 2 saves the value 168 to Application.totalTicketsSold.
11 Order 2 exits the lock tag, which frees the Application scope lock. ColdFusion can process another order.
320
By placing the code that sets all of the related session variables in a single cflock tag, you ensure that all the variables
get set together. In other words, setting all of the variables becomes an atomic, or single, operation. It is like a database
transaction, where everything in the transaction happens, or nothing happens. In this example, the order details for
the first order all get set, and then they are replaced with the details from the second order.
For more examples of using locking in applications, see Examples of cflock on page 324.
Lock types
The cflock tag offers two modes of locking, specified by the type attribute:
Exclusive locks (the default lock type) Allow only one request to process the locked code. No other requests can run
executing. No requests can run code inside the tag while a request has an exclusive lock.
Enclose code that only reads or tests session, application, or server variables in read-only cflock tags. You specify a
read-only lock by setting the type="readOnly" attribute in the cflock tag, for example:
<cflock scope="Application" timeout="10" type="readOnly">
<cfif IsDefined("Application.dailyMessage")>
<cfoutput>#Application.dailyMessage#<br></cfoutput>
</cfif>
</cflock>
321
Although ColdFusion does not prevent you from setting shared variables inside read-only lock tag, doing so loses the
advantages of locking. As a result, be careful not to set any session, application, or server variables inside a read-only
cflock tag body.
Note: You cannot upgrade or downgrade a lock from one type to another. In other words, do not nest an exclusive lock
in a read-only lock of the same name or scope; the exclusive lock will always time out. Also, do not nest a read-only lock
inside an exclusive lock with the same name or scope; doing so has no effect.
Lock scopes and names
The cflock tag prevents simultaneous access to sections of code, not to variables. If you have two sections of code that
access the same variable, they must be synchronized to prevent them from running simultaneously. You do this by
identifying the locks with the same scope or name attributes.
Note: ColdFusion does not require you to identify exclusive locks. If you omit the identifier, the lock is anonymous and
you cannot synchronize the code in the cflock tag block with any other code. Anonymous locks do not cause errors when
they protect a resource that is used in a single code block, but they are bad programming practice. You must always
identify read-only locks.
Controlling access to data with the scope attribute
When the code that you are locking accesses session, application, or server variables, synchronize access by using the
cflockscope attribute.
You can set the attribute to any of the following values:
Scope
Meaning
Server
All code sections with this attribute on the server share a single lock.
Application
All code sections with this attribute in the same application share a single lock.
Session
All code sections with this attribute that run in the same session of an application share a single lock.
Request
All code sections with this attribute that run in the same request share a single lock. You use this scope only if your
application uses the cfthread tag to create multiple threads in a single request. Locking the Request scope also
locks access to Variables scope data. For more information on locking the Request scope, see Locking thread data
and resource access on page 334.
When code is running in a cflock tag block with the type attribute set to Exclusive, code in cflock tag blocks
with the same scope attribute is not allowed to run. They wait until the code with the exclusive lock completes.
When code in a cflock tag block with the type readOnly is running, code in other cflock tag blocks with the same
scope attribute and the readOnlytype attribute can run, but any blocks with the same scope attribute and an
Exclusive type cannot run and must wait until all code with the read-only lock completes. However, if a read-only
lock is active and code with an exclusive lock with the same scope or name is waiting to execute, read-only requests
using the same scope or name that are made after the exclusive request is queued must wait until code with the
exclusive lock executes and completes.
Controlling locking access to files and CFX tags with the name attribute
The cflockname attribute provides a second way to identify locks. Use this attribute when you use locks to protect
code that manges file access or calls non-thread-safe CFX code.
When you use the name attribute, specify the same name for each section of code that accesses a specific file or a specific
CFX tag.
322
For example, if you want to assign the results of a query to a session variable, first get the query results using a Variables
scope variable in unlocked code. Then, assign the query results to a session variable inside a locked code section. The
following code shows this technique:
<cfquery name="Variables.qUser" datasource="#request.dsn#">
SELECT FirstName, LastName
FROM Users
WHERE UserID = #request.UserID#
</cfquery>
<cflock scope="Session" timeout="5" type="exclusive">
<cfset Session.qUser = Variables.qUser>
</cflock>
If the code block is larger, ColdFusion spends more time inside the block, which can increase the number of times
an application waits for the lock to released.
Each lock requires processor time. The more locks you have, the more processor time is spent on locking code.
323
User 1
User 2
Tries to lock the Session scope, but the Session scope is already locked
by User 1.
Neither users request can proceed, because it is waiting for the other to complete. The two are deadlocked.
Once a deadlock occurs, neither of the users can do anything to break the deadlock, because the execution of their
requests is blocked until the deadlock is resolved by a lock time-out.
You can also cause deadlocks if you nest locks of different types. An example of this is nesting an exclusive lock inside
a read-only lock of the same scope or same name.
To avoid a deadlock, lock code sections in a well-specified order, and name the locks consistently. In particular, to lock
access to the Server, Application, and Session scopes, do so in the following order:
1 Lock the Session scope. In the cflock tag, specify scope="Session".
2 Lock the Application scope. In the cflock tag, specify scope="Application".
3 Lock the Server scope. In the cflock tag, specify scope="Server".
4 Unlock the Server scope.
5 Unlock the Application scope.
6 Unlock the Session scope.
Note: You can skip any pair of lock and unlock steps in the preceding list if you do not need to lock a particular scope. For
example, you can omit steps 3 and 4 if you do not need to lock the Server scope.
Copying shared variables into the Request scope
You can avoid locking some shared-scope variables multiple times during a request by doing the following:
1 Copy the shared-scope variables into the Request scope in code with an exclusive lock in the Application.cfc
onRequestStart method or the Application.cfm page.
2 Use the Request scope variables on your ColdFusion pages for the duration of the request.
3 Copy the variables back to the shared scope in code with an exclusive lock in the Application.cfc onRequestEnd
check for the existence of the flag, and assign the result to a local variable.
2 Outside the cflock bock, test the value of the local variable
324
3 If it the local variable indicates that the application variables are not initialized, get an exclusive Application scope lock.
4 Inside the lock, again test the Application scope flag, to make sure that another page has not set the variables
Examples of cflock
The following examples show how to use cflock blocks in a variety of situations.
325
<cfapplication name="ETurtle"
sessiontimeout=#createtimespan(0,1,30,0)#
sessionmanagement="yes">
<!--- Initialize the Session and Application
variables that will be used by E-Turtleneck. Use
the Session lock scope for the session variables. --->
<cflock scope="Session"
timeout="10" type ="Exclusive">
<cfif not IsDefined("session.size")>
<cfset session.size = "">
</cfif>
<cfif not IsDefined("session.color")>
<cfset session.color = "">
</cfif>
</cflock>
<!--- Use the Application scope lock for the Application.number variable.
This variable keeps track of the total number of turtlenecks sold.
The following code implements the scheme shown in the Locking Application
variables effectively section --->
<cfset app_is_initialized = "no">
<cflock scope="Application" type="readonly">
<cfset app_is_initialized = IsDefined("Application.initialized")>
</cflock>
<cfif not app_is_initialized >
<cflock scope="application" timeout="10" type="exclusive">
<cfif not IsDefined("Application.initialized") >
<cfset Application.number = 1>
<cfset Application.initialized = "yes">
</cfif>
</cflock>
</cfif>
<!--- Always display the number of turtlenecks sold --->
<cflock scope="Application"
timeout="10"
type ="ReadOnly">
<cfoutput>
E-Turtleneck is proud to say that we have sold
#Application.number# turtlenecks to date.
</cfoutput>
</cflock>
The remaining sample code could appear inside the application page where customers place orders:
326
<html>
<head>
<title>cflock Example</title>
</head>
<body>
<h3>cflock Example</h3>
<cfif IsDefined("Form.submit")>
<!--- Lock session variables --->
<!--- Note that we use the automatically generated Session
ID as the order ID --->
<cflock scope="Session"
timeout="10" type="ReadOnly">
<cfoutput>Thank you for shopping E-Turtleneck.
Today you have chosen a turtleneck in size
<b>#form.size#</b> and in the color <b>#form.color#</b>.
Your order ID is #Session.sessionID#.
</cfoutput>
</cflock>
<!--- Lock session variables to assign form values to them. --->
<cflock scope="Session"
timeout="10"
type="Exclusive">
<cfparam name=Session.size default=#form.size#>
<cfparam name=Session.color default=#form.color#>
</cflock>
<
!--- Lock the Application scope variable application.number to
update the total number of turtlenecks sold. --->
<cflock scope="Application"
timeout="30" type="Exclusive">
<cfset application.number=application.number + 1>
</cflock>
<!--- Show the form only if it has not been submitted. --->
<cfelse>
<form action="cflock.cfm" method="Post">
<p> Congratulations! You have just selected
the longest-wearing, most comfortable turtleneck
in the world. Please indicate the color and size
you want to buy.</p>
<table cellspacing="2" cellpadding="2" border="0">
<tr>
<td>Select a color.</td>
<td><select type="Text" name="color">
<option>red
<option>white
<option>blue
<option>turquoise
<option>black
327
<option>forest green
</select>
</td>
</tr>
<tr>
<td>Select a size.</td>
<td><select type="Text" name="size">
<option>small
<option>medium
<option>large
<option>xlarge
</select>
</td>
</tr>
<tr>
<td></td>
<td><input type="Submit" name="submit" value="Submit">
</td>
</tr>
</table>
</form>
</cfif>
</body>
</html>
Note: In this simple example, the Application.cfm page displays the Application.number variable value. Because the
Application.cfm file is processed before any code on each ColdFusion page, the number that displays after you click the
submit button does not include the new order. One way you can resolve this problem is by using the OnRequestEnd.cfm
page to display the value at the bottom of each page in the application.
328
An application that aggregates information from multiple external sources, that takes significant time to respond,
has the code that gets information from each source in a separate thread. This way, the application starts all requests
quickly and has to wait only until the last response is received, instead of having to wait for a response to each
request before the next request can start. One example of such usage is an RSS or Atom feed aggregator.
A page that sends many mail messages runs the code that sends the mail messages in a separate thread and doesnt
wait for it to complete to continue processing. The thread that sends the mail messages continues processing after
the page-level processing is completed and the application starts processing another page.
An application does maintenance of user data, such as using update queries, deleting records, and so on, whenever
a user logs into the site. If the application does the maintenance in a separate thread, the user gets an immediate
response after logging in, without having to wait for the updates to complete.
When ColdFusion processes a page, the page executes in a single thread, called the page thread. The cfthread tag lets
you create additional threads that can process independently of the page thread, and lets you synchronize thread
processing, for example, by having the page thread wait until threads that you create complete their processing.
329
End a thread. You typically end a running thread if there is an error, or if it is still processing after a long time.
Have the page or a thread wait until one or more other threads have completed processing before proceeding with
its processing, called joining the threads. You typically join threads when one thread requires the results from
another thread. For example, if a page uses multiple threads to get several news feeds for display, it joins all the feed
threads before it displays the results.
Each thread runs the code inside a cfthread tag body and normally exits when the tag body code completes
processing.
Starting a thread
You start a thread by using a cfthread tag with an action attribute value of run. CFML code within the cfthread
tag body executes on a separate thread while the page request thread continues processing. Only the page thread can
create other threads. A thread that you create with a cfthread tag cannot create a child thread, so you cannot have
multiple nested threads.
Optionally, when you start the thread, you can specify a priority level of high, normal (the default), or low to specify
the relative amount of time that the processor should devote to the thread. Page-level code always runs at normal
priority, so you can give your threads more or less processing time than the page.
For more information on using thread attributes, see The Attributes scope and thread attributes on page 333.
Suspending a thread
In some cases, one thread must wait until a second thread completes some operations, but should not wait until the
second thread completes all processing, so you cannot just join the threads. For example, one thread might do
initialization that multiple threads require, and then it might continue with additional processing. The other threads
could suspend themselves until initialization is complete.
The Sleep function and cfthread tag with a sleepaction attribute provide two equivalent mechanisms for doing
such synchronization. They suspend the thread processing for a specified period of time. A code loop could test a
condition variable and sleep for a period before retesting the condition. When the condition is true (or a value is
reached, or some other test is valid), the program exits the loop and the thread continues processing.
The following example shows how one thread could use a sleep function to wait for a second thread to perform some
actions.
330
<!--- ThreadA loops to simulate an activity that might take time. --->
<cfthread name="threadA" action="run">
<cfset thread.j=1>
<cfloop index="i" from="1" to="1000000">
<cfset thread.j=thread.j+1>
</cfloop>
</cfthread>
<!--- ThreadB loops, waiting until threadA finishes looping 40000 times.
the loop code sleeps 1/2 second each time. --->
<cfthread name="threadB" action="run">
<cfscript>
thread.sleepTimes=0;
thread.initialized=false;
while ((threadA.Status != "TERMINATED") && (threadA.j < 400000)) {
sleep(500);
thread.sleeptimes++;
}
// Don't continue processing if threadA terminated abnormally.
If (threadA.Status != "TERMINATED") {
thread.initialized=true;
// Do additional processing here.
}
</cfscript>
</cfthread>
<!Join the page thread to thread B. Don't join to thread A.--->
<cfthread action="join" name="threadB" timeout="10000" />
<!--- Display the thread information. --->
<cfoutput>
current threadA index value: #threadA.j#<br />
threadA status: #threadA.Status#<br>
threadB status: #threadB.Status#<br>
threadB sleepTimes: #threadB.sleepTimes#<br>
Is threadB initialized: #threadB.initialized#<br>
</cfoutput>
Ending a thread
If a thread never completes processing (is hung), it continues to occupy system resources, so it is good practice to have
your application check for hung threads and end them. Also consider ending threads that take excessive time to
process and might significantly reduce the responsiveness of your application or server.
To end a thread, use the cfthread tag with an action attribute value of terminate, as the following code snippet
shows.
331
Note: You can also have the ColdFusion Sever Monitor automatically check for and terminate hung threads.
Joining threads
You use the cfthreadtag with an action attribute value of join to join two or more threads. You join threads when
one thread depends on one or more other threads completing before it can do some processing. For example, a page
can start multiple threads to do processing and join them before it processes the thread results. By default, the join
action stops the current thread from doing further processing until all the specified threads complete processing.
You can use a timeout attribute to specify the number of milliseconds that the current thread waits for the thread or
threads being joined to finish. If any thread does not finish by the specified time, the current thread proceeds without
waiting for the remaining thread or threads to complete.
The following code, for example, joins three threads to the current thread (often, the main page thread). The current
thread waits up to six seconds for the other threads to complete, and continues processing if one or more threads do
not complete by then.
332
If the timeout attribute value is 0, the default value, the current thread continues waiting until all joining threads
finish. In this case, if the current thread is the page thread, the page continues waiting until the threads are joined, even
if you specify a page time-out. As a general rule, specify a timeout value to limit hung threads.
Thread scopes
Each thread has three special scopes:
These two lines are equivalent, with one exception: If you use the var keyword, the assignment code must immediately
follow the cfthread tag, before any other CFML tags.
The Thread scope
The Thread scope contains thread-specific variables and metadata about the thread. Only the owning thread can write
data to this scope, but the page thread and all other threads in a request can read the variable values in this scope.
Thread scope data remains available until the page and all threads that started from the page finish, even if the page
finishes before the threads complete processing.
To create a Thread scope variable, in the cfthread tag body, use the keyword Thread or the name of the thread (for
example, myThread) as a prefix. the following examples of creating a Thread scope variable are equivalent:
<cfset Thread.myValue = 27>
<cfset myThread.myValue = 27>
To access a threads Thread scope variables outside the thread, prefix the variable with the threads name, as in the
following example:
<cfset nextValue=myThread.myValue + 1>
333
Thread scope variables are only available to the page that created the thread or to other threads created by that page.
No other page can access the data. If one page must access another pages Thread scope data, you must place the data
in a database or file and access it from there.
The Thread scope of each thread is a subscope of a special scope, cfthread, that lasts as long as the request, or until the
last thread that it starts completes, whichever is longer. Thus, if you have two threads, myThread1 and myThread2,
you can access their Thread scopes as cfthread.myThread1 and cfthread.myThread2 until all threads and the request
complete. In most cases, there is no need to use the cfthread scope directly. However, you can use the cfthread scope
name in either of the following situations:
1 If you generate the thread name dynamically, you can avoid using the Evaluate function by using the cfthread
scope with associative array notation, as the following code snippet shows:
<cfset threadname="thread_#N#">
...
<!--- The following two lines are equivalent --->
<cfset threadscopeForNthThread = cfthread[threadname] >
<cfset threadscopeForNthThread = Evaluate(threadname) >
2 If you have a thread with the same name as a Variables scope variable, you can access that threads Thread scope
only by prefacing the Thread name with cfthread. Otherwise, you access the Variables scope variable, or get an
error.
The Attributes scope and thread attributes
The Attributes scope contains attributes that are passed to the thread, either individually or in the
attributeCollection attribute. The Attributes scope is available only within the thread and only for the life of the
thread.
ColdFusion makes a complete (deep) copy of all the attribute variables before passing them to the thread; therefore,
the values of the variables inside the thread are independent of the values of any corresponding variables in other
threads, including the page thread. For example, if you pass a CFC instance as an attribute to a thread, the thread gets
a complete new copy of the CFC, including the contents of its This scope at the time that you create the thread. Any
changes made to the original CFC outside the thread, for example, by calling a CFC function, have no effect on the
copy that is in the thread. Similarly, any changes to the CFC instance in the thread have no effect on the original CFC
instance.
Copying the data ensures that the values passed to threads are thread-safe, because the attribute values cannot be
changed by any other thread. If you do not want duplicate data, do not pass it to the thread as an attribute or in the
attributeCollection attribute. Instead, keep the data in a scope that the thread can access. An example of an object
that should not be passed to the thread as an attribute is a singleton CFC that should never be duplicated. The singleton
CFC must be kept in some shared scope and accessed by threads. For more information, see the Using other scopes
on page 334.
Because ColdFusion copies all attributes by value, you can have multiple threads, for example, threads created
dynamically in a loop, that use the same attribute names, but where each thread gets a different value, as shown in the
following code excerpt, which creates separate threads to copy each of several files in a directory:
<cfloop query="dir">
<cfset threadname = "thread_" & #i#>
<cfset i=i+1>
<cfthread name="#threadname#" filename="#dir.name#">
<cffile action="COPY" source="#src#\#filename#"
destination="#dest#\#filename#\">
</cfthread>
</cfloop>
334
If multiple threads modify a Variables or Request scope variable, use a Request scope lock to control access to the
code that uses the variable to prevent deadlocks and race conditions. Similarly, use a Request scope lock around
code that accesses built-in data structures or subscopes of the Variables scope, such as the Forms variable, that you
change in multiple threads.
Multiple threads should not try to access any other shared resource simultaneously. For example, do not use the
same FTP connection from multiple threads. To prevent this behavior, place the code that uses the resource in
named cflock tags. Use the same name attribute for all cflock tags around code that uses a specific resource.
For more information on locking code, see cflock and Locking code with cflock on page 318.
Metadata variables
The Thread scope contains the following variables that provide information about the thread, called metadata.
Variable
Description
Elapsedtime
The amount of processor time that has been spent handling the thread.
Error
A ColdFusion error structure that contains the keys that you can access in a cfcatch tag. This variable has a value
only if an unhandled error occurred during thread processing. For information on handling thread errors, see
Handling ColdFusion thread errors on page 336.
Name
Output
Output text that the thread generates. Threads cannot display output directly. For more information see Handling
thread output on page 336.
335
Variable
Description
Priority
The thread processing priority, as specified when you created the thread.
Starttime
Status
The current status of the thread. For information on using the Status in an application, see Using the thread status
on page 336.
As with other variables in the Thread scope, thread metadata is available to all of a pages threads by specifying the
thread name as a variable prefix. For example, the page thread can get the current elapsed time of the myThread1
thread from the myThread1.ElapsedTime variable.
The metadata is available from the time that you create the thread until the time when the page and all threads started
on the page complete processing, even if the page finishes before the threads finish. This way, you can get thread
output, error information, and processing information during and after the time when the thread is processing.
336
Meaning
NOT_STARTED
RUNNNG
TERMINATED
COMPLETED
WAITING
The thread has run a cfthread tag with action="join", and one or more of the threads being joined have
not yet completed.
Applications can check the thread status to manage processing. For example, an application that requires results from
a thread specifies a time-out when it joins the thread; in this case, it can check for the COMPLETED status to ensure
that the thread has completed processing and the join did not just result from a time-out. Similarly, an application can
check the status value of threads that might not start or might not complete normally, and terminate it if necessary.
The example in Ending a thread on page 330 checks thread status and terminates any threads with RUNNING or
NOT_STARTED status.
ColdFusion places all output that you generate inside a thread, such as HTML and plain text, or the generated
output of a cfoutput tag, in the Thread scope output metadata variable. The page-level code can display the
contents of this variable by accessing the threadName.output variable.
All tags and tag actions that directly send output to the client (instead of generating page text such as HTML
output), do not work inside the thread. For example, to use the cfdocument or cfreport tags in a thread, specify
a filename attribute; to use a cfpresentation tag, use a directory attribute.
thread.
337
2 Handle the error outside the thread by using the thread error information that is available to the page and other
threads in the Thread scope threadName.Error variable. Application code can check this variable for error
information. For example, after you join to a thread that had an error, you could check the threadname.status
variable for a value of terminated, which indicates that the thread terminated abnormally. You could then check
the threadName.Error variable for information on the termination cause.
In this case, query q1 is not included in the transaction that contains query q2. To include both queries in the
transaction, you must place the complete transaction in a single thread, using a structure such as the following:
<cfthread name ="t1" ...>
<cftransaction>
<cfquery name="q1" ...>
...
</cfquery>
<cfquery name="q2" ...>
...
</cfquery>
</cftransaction>
</cfthread>
<cfthread action="join" name="t1" ... />
338
<!--- Run this code if the feed URL form has been submitted. --->
<cfif isDefined("Form.submit")>
<cfloop index="i" from="1" to="3">
<!--- Use array notation and string concatenation to create a variable
for this feed. --->
<cfset theFeed = Form["Feed"&i]>
<cfif theFeed NEQ "">
<!--- Use a separate thread to get each of the feeds. --->
<cfthread action="run" name="t#i#" feed="#theFeed#">
<cffeed source="#feed#"
properties="thread.myProps"
query="thread.myQuery">
</cfthread>
<cfelse>
<!--- If the user didn't fill all fields, show an error message. --->
<h3>This example requires three feeds.<br />
Click the Back button and try again.</h3>
<cfabort>
</cfif>
</cfloop>
<!--- Join the three threads. Use a 6 second timeout. --->
<cfthread action="join" name="t1,t2,t3" timeout="6000" />
<!--- Use a loop to display the results from the feeds. --->
<cfloop index="i" from="1" to="3">
<!--- Use the cfthread scope and associative array notation to get the
Thread scope. --->
<cfset feedResult=cfthread["t#i#"]>
<!--- Display feed information only if you got items,
for example, the feed must complete before the join. --->
<cfif isDefined("feedResult.myQuery")>
<cfoutput><h2>#feedResult.myProps.title#</h2></cfoutput>
<cfoutput query="feedResult.myQuery">
<p><a href="#RSSLINK#">#TITLE#</a></p>
</cfoutput>
</cfif>
</cfloop>
</cfif>
<!--- The form for entering the feeds to aggregate. --->
<cfform>
<h3>Enter three RSS Feeds</h3>
<cfinput type="text" size="100" name="Feed1" validate="url"
value="http://rss.adobe.com/events.rss?locale=en"><br />
<cfinput type="text" size="100" name="Feed2" validate="url"
value="http://weblogs.macromedia.com/dev_center/index.rdf"><br />
<cfinput type="text" size="100" name="Feed3" validate="url"
value="http://rss.adobe.com/studio.rss?locale=en"><br />
<cfinput type="submit" name="submit">
</cfform>
339
Securing Applications
Resource security (Adobe ColdFusion Standard) or sandbox security (Adobe ColdFusion Enterprise) restricts access to
specific resources, such as tags and files. You use the ColdFusion Administrator to configure sandbox or resource
security, and structure an application to take advantage of this security.
User security depends on a user identity. You can implement user security in Adobe ColdFusion applications.
For detailed information on using Administrator-controlled security features, see Configuring and Administering
ColdFusion.
The cfqueryparam tag: This tag helps prevent users from injecting malicious SQL expressions. For more
information on using this tag for database security, see Enhancing security with cfqueryparam on page 416,
Scriptprotect setting: This setting helps protect against cross-site scripting attacks. You set this value with the
ColdFusion Administrator Enable Global Script Protection setting, in the Application.cfc This.scriptprotect
variable, or in the corresponding cfapplication tag scriptprotect attribute. For more information on this
feature, see cfapplication in the CFML Reference. For information on Application.cfc see Defining the application
and its event handlers in Application.cfc on page 241.
Encryption and hashing functions: The Encrypt, Decrypt, and Hash functions let you select a secure algorithm
for encrypting and decrypting data or generating a hash fingerprint. You can select from among several secure
algorithms that underlying Java security mechanisms support. For encryption, these include, AES, Blowfish, DES
and Triple DES. For more information, see the Encrypt, Decrypt, and Hash, functions in the CFML Reference.
Data validation tools ColdFusion includes a variety of tools for validating form input and other data values,
including ways to ensure that users do not submit malicious form data. For information on data validation see
Validating Data on page 743; for specific information on security and validation, see Security considerations
on page 747.
Resource/Sandbox The ColdFusion Administrator can limit access to ColdFusion resources, including selected tags
and functions, data sources, files, and host addresses. In the Standard Edition, you configure a single set of resource
limitations that apply to all your ColdFusion applications.
In the Enterprise Edition, you can have multiple sandboxes, based on the location of your ColdFusion pages, each with
its own set of resource limitations. You can confine applications to secure areas, thereby flexibly restricting the access
that the application has to resources.
User ColdFusion applications can require users to log in to use application pages. You can assign users to roles
(sometimes called groups); ColdFusion pages can determine the logged-in users roles or ID and selectively determine
what to do based on this information. User security is also called authentication and authorization security.
Note: You can also use the cfencode utility, located in the cf_root/bin directory, to obscure ColdFusion pages that you
distribute. Although this technique cannot prevent persistent hackers from determining the contents of your pages, it does
prevent inspection of the pages. The cfencode utility is not available on OS X.
340
ColdFusion Standard refers to its resource-based security as resource security. It lets you specify a single set of
limitations on access to ColdFusion resources that apply to all ColdFusion applications.
ColdFusion Enterprise refers to its resource-based security as sandbox security. Sandbox security is a superset of
resource security. Sandbox security lets you create multiple sandboxes, each corresponding to a different directory.
For each sandbox, you specify a set of resource limitations that apply to all ColdFusion pages in the sandbox
directory and its subdirectories. If you create a sandbox that is a subdirectory of a sandbox, the subdirectorys rules
override the parent directorys rules.
The ColdFusion Administrator Resource Security page (in Standard) and Sandbox Security page (in Enterprise) let
you enable resource-based security. In ColdFusion Standard, the page lets you configure the resource settings that
apply to all your ColdFusion applications. In ColdFusion Enterprise, the page lets you create sandboxes and configure
the resource limitations for each sandbox individually.
Resource control
ColdFusion lets you control access to the following resources:
Resource
Description
Data sources
CF tags
Prevents pages from using CFML tags that access external resources. You can prevent pages in the directory from
using any or all of the following tags:
cfcollection, cfcontent, cfcookie, cfdirectory, cfdocument, cfexecute, cffile, cfftp, cfgridupdate, cfhttp,
cfhttpparam, cfindex, cfinsert, cfinvoke, cfldap, cflog, cfmail, cfobject, cfobjectcache, cfpop, cfquery, cfregistry,
cfreport, cfschedule, cfsearch, cfstoredproc, cftransaction, cfupdate
CF functions
Prevents pages from using CFML functions that access external resources. You can prevent pages from using any
or all of the following functions:
CreateObject (COM, Java, Web Service),DirectoryExists. ExpandPath, FileExists, GetBaseTemplatePath,
GetDirectoryFromPath, GetFileFromPath, GetGatewayHelper, GetProfileString, GetTempDirectory, GetTempFile,
GetTemplatePath, SendGatewayMessage, SetProfileString
Files/directories
Sets read, write, execute, and delete access to specified directories, directory trees, or files.
Server/ports
Controls access from ColdFusion to IP addresses and port numbers. You can specify host names or numeric
addresses, and you can specify individual ports and port ranges.
Note: For more information on configuring resource and sandbox security, see Configuring and Administering
ColdFusion and the ColdFusion Administrator online Help.
Sandbox security
In ColdFusion Enterprise, sandbox security lets you apply different sets of rules to different directory structures. Use
it to partition a shared hosting environment so that a number of applications with different purposes, and possibly
different owners, run securely on a single server. When multiple applications share a host, you set up a separate
directory structure for each application, and apply rules that let each application access only its own data sources and
files.
Sandbox security also lets you structure and partition an application to reflect the access rights that are appropriate to
different functional components. For example, if your application has both employee inquiry functions and HR
functions that include creating, accessing, and modifying sensitive data, you could structure the application as follows:
HR pages go in one directory with access rules that enable most activities.
341
Employee pages go in another directory whose rules limit the files they modify and the tags they use.
Pages required for both HR and employee functions go in a third directory with appropriate access rules.
(or, in some cases if you use web server authentication, the web server) maintains the user ID information while the
user is logged-in.
Authorization Ensures that the logged-in user is allowed to use a page or perform an operation. Authorization is
typically based on one or more roles (sometimes called groups) to which the user belongs. For example, in an employee
database, all users could be members of either the employee role or the contractor role. They could also be members
of roles that identify their department, position in the corporate hierarchy, or job description. For example, someone
could be a member of some or all of the following roles:
Employees
Human Resources
Benefits
Managers
Roles enable you to control access in your application resources without requiring the application to maintain
knowledge about individual users. For example, suppose you use ColdFusion for your companys intranet. The
Human Resources department maintains a page on the intranet on which all employees can access timely information
about the company, such as the latest company policies, upcoming events, and job postings. You want everyone to be
able to read the information, but you want only certain authorized Human Resources employees to be able to add,
update, or delete information.
Your application gets the users roles from the user information data store when the user logs in, and then enables
access to specific pages or features based on the roles. Typically, you store user information in a database, LDAP
directory, or other secure information store.
You also use the user ID for authorization. For example, to let employees view customized information about their
salaries, job levels, and performance reviews. You certainly would not want one employee to view sensitive
information about another employee, but you would want managers to be able to see, and possibly update, information
about their direct reports. By employing both user IDs and roles, you ensure that only the appropriate people access
or work with sensitive data.
342
The following image shows a typical flow of control for user authentication and authorization. Following sections
expand on this diagram to describe how you implement user security in ColdFusion.
User requests a
page.
Is a user
logged in
Yes
No
Is the user
authenticated?
Yes
No
Is user in role
needed for activity?
Yes
User is authenticated and
authorized.
Do secured operations.
Authenticating users
Use either, or both, of the following forms of authentication to secure your ColdFusion application:
Web server authentication, where the web server authenticates the user and does not allow access to the website by
users without valid login IDs
Application authentication, where the ColdFusion application authenticates the user and does not allow access to
the application by users without valid login IDs
Web server authentication
All major web servers support basic HTTP authentication. Some web servers also support other authentication
methods, including Digest HTTP authentication and Microsoft NTLM authentication.
343
Note: Dreamweaver and Studio MX do not support NTLM security with RDS. Therefore, you cannot use RDS with these
applications if the ColdFusion RDS servlet (cf_root/CFIDE/main/ide.cfm) is in a directory that is protected using NTLM
security.
In web server authentication, the web server requires the user to log in to access pages in a particular directory, as
follows:
1 When the user first requests a page in the secured directory, the web server notifies the browser that the requested
original request.
4 The web server checks the user ID and password, using its own user authentication mechanism.
5 If the user logs in successfully, the browser caches the authentication information and sends it in an HTTP
Authorization header with every subsequent page request from the user.
6 The web server processes the requested page and all future page requests from the browser that contain the HTTP
344
Enable the Session scope in the ColdFusion Administrator and the Application.cfc initialization code or
cfapplication tag.
After the user logs in, the user ID and password are not passed between the server and the browser.
The login information and the session share a single time-out. You do not have to manually synchronize sessions
and logins.
If you use server clusters, the Session scope login ID is available across the cluster. For more information on server
clustering, see Configuring and Administering ColdFusion.
If you do not enable the Session scope, the authentication information is not kept in a persistent scope. Instead, the
detailed login information is placed in a memory-only cookie (CFAUTHORIZATION_applicationName) with a
base64-encoded string that contains the user name, password, and application name. The client sends this cookie to
the web server each time it makes a page request while the user is logged-in. Use SSL for all page transactions to protect
the user ID and password from unauthorized access.
Using ColdFusion security without cookies
Implement a limited-lifetime form of ColdFusion security if the users browser does not support cookies. In this case
you do not use the cflogin tag, only the cfloginuser tag. It is the only time you should use the cfloginuser tag
outside a cflogin tag.
Without browser cookies, the effect of the cfloginuser tag is limited to a single HTTP request. Provide your own
authentication mechanism and call cfloginuser on each page on which you use ColdFusion login identification.
345
Purpose
cflogin
A container for user authentication and login code. The body of the tag runs only if the user is not logged
in. When using application-based security, you place code in the body of the cflogin tag to check the
user-provided ID and password against a data source, LDAP directory, or other repository of login
identification. The body of the tag includes a cfloginuser tag (or a ColdFusion page that contains a
cfloginuser tag) to establish the authenticated users identity in ColdFusion.
cfloginuser
Identifies (logs in) a user to ColdFusion. Specifies the users ID, password, and roles. This tag is typically used
inside a cflogin tag.
The cfloginuser tag requires three attributes, name, password, and roles, and does not have a body.
The roles attribute is a comma-delimited list of role identifiers to which the logged-in user belongs. All
spaces in the list are treated as part of the role names, so you should not follow commas with spaces.
While the user is logged-in to ColdFusion, security functions access the user ID and role information.
cflogout
Logs out the current user. Removes knowledge of the user ID and roles from the server. If you do not use
this tag, the user is automatically logged out as described in Logging out users on page 348.
The cflogout tag does not take any attributes, and does not have a body.
cfNTauthenticate
Authenticates a user name and password against the NT domain on which ColdFusion server is running,
and optionally retrieves the users groups.
cffunction
If you include a roles attribute, the function executes only when there is a logged-in user who belongs to
one of the specified roles.
IsUserInAnyRole
GetAuthUser
Use
idleTimeout
If no page requests occur during the idleTimeout period, ColdFusion logs out the user. The default is 1800
seconds (30 mins). This is ignored if login information is stored in the Session scope.
applicationToken
Limits the login validity to a specific application as specified by a ColdFusion pages cfapplication tag. The
default value is the current application name.
cookieDomain
Specifies the domain of the cookie used to mark a user as logged-in. You use cookieDomain if you have a
clustered environment (for example, x.acme.com, x2.acme.com, and so on). This lets the cookie work for
all the computers in the cluster.
346
ColdFusion uses the applicationToken value to generate a unique identifier that enforces this rule. The default
applicationToken value is the current application name, as specified by a cfapplication tag or Application.cfc
unitization code. In normal use, you need not specify an applicationToken value in the cflogin tag.
Specifying the Internet domain
Use the cookieDomain attribute to specify the domain of the cookie used to mark a user as logged-in. You use
cookieDomain if you have a clustered environment (for example, www.acme.com, www2.acme.com, and so on). This
lets the cookie work for all computers in the cluster. For example, to ensure that the cookie works for all servers in the
acme.com domain, specify cookieDomain=".acme.com". To specify a domain name, start the name with a period.
Important: Before setting the cookie domain, consider the other applications or servers in the broader domain might have
access to the cookie. For example, a clustered payroll application at payroll1.acme.com, payroll2.acme.com, and so on,
might reveal sensitive information to the test computer at test.acme.com, if the cookie domain is broadly set to
.acme.com.
Submission of a login form that contains input fields with the names j_username and j_password.
A request that uses HTTP Basic authentication and, therefore, includes an Authorization header with the user name
and password.
A message from the Flash Remoting gatewayConnection object that has the setCredentials method set.
A request that uses NTLM or Digest authentication. In this case, the user name and password are hashed using a
one-way algorithm before they are placed in the Authorization header; ColdFusion gets the user name from the web
server and sets the cflogin.password value to the empty string.
You use the first three techniques with application authentication, and the last technique with web server
authentication. The cflogin structure provides a consistent interface for determining the users login ID and password,
independent of the technique that you use for displaying the login form.
Important: Login forms send the user name and password without encryption. Basic HTTP authentication sends the user
name and password in a base64-encoded string with each request; this format can easily be converted back to plain text.
Use these techniques only with https requests, or when you are not concerned about password security.
Provide login information to your application for authentication as follows:
Use a login form to get user information
When you build an application that gets the User ID and password using a login form, the cflogin tag checks for the
existence of a cflogin structure containing the users login information. If the structure does not exist, it displays a login
form, typically using a cfinclude tag on a login page; the following code shows this use.
In the Application.cfc onRequestStart method, or a ColdFusion page or CFC method called by the method, you have
the following:
347
<cflogin>
<cfif NOT IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<!--- Code to authenticate the user based on the cflogin.user and
cflogin.password values goes here. --->
<!--- If User is authenticated, determine any roles and use a line like the
following to log in the user. --->
<cfloginuser name="#cflogin.name#" Password = "#cflogin.password#"
roles="#loginQuery.Roles#">
</cfif>
</cflogin>
348
<cflogin>
<cfif NOT IsDefined("cflogin")>
<cfheader statuscode="401">
<cfheader name="www-Authenticate" value="Basic
realm=""MM Wizard #args.authtype# Authentication""">
</cfif>
<cfabort>
<cfelse>
<!--- code to authenticate the user based on the cflogin.user and
cflogin.password values goes here. --->
</cflogin>
For more information on using Flash Remoting, see Using the Flash Remoting Service on page 606 and Using Flash
Remoting Update on page 619.
The application uses a cflogout tag to log out the user, usually in response to the user clicking a log-out link or
button.
If your application uses the Session scope for login information, the session ends.
If your application does not use the Session scope for login information, the user does not request a new page for
the cflogin tag idleTimeout period.
If your application does not use Session scope for login information, or if you use J2EE-based session identification,
the user closes all browser windows.
Logging out a user by using the cflogout tag does not close the users session, but if you use session login storage, it
does remove the login information (the Session.cfauthorization variable) from the Session scope. For more
information on ending sessions, see Ending a session on page 315.
349
Important: If you use web serverbased authentication or any form authentication that uses a Basic HTTP
Authorization header, the browser continues to send the authentication information to your application until the user
closes the browser, or in some cases, all open browser windows. As a result, after the user logs out and your application
uses the cflogout tag, until the browser closes, the cflogin structure in the cflogin tag will contain the logged-out users
UserID and password. If a user logs out and does not close the browser, another user can access pages with the first users
login.
Security scenarios
There are two detailed security scenarios. The first scenario uses the web server to perform the authentication against
its user and password database. The second scenario uses ColdFusion for all authentication and authorization.
the web server displays a login page and logs in the user. The web server handles all user authentication.
2 Because the user requested a ColdFusion page, the web server hands the request to ColdFusion.
3 When ColdFusion receives a request for a ColdFusion page, it instantiates the Application.cfc and runs
onRequestStart method. If you use an Application.cfm page in place of the Application.cfc, it runs the contents
of the Application.cfm page before it runs the requested page. The onRequestStart method or Application.cfm
page contains a cflogin tag. ColdFusion executes the cflogin tag body if the user is not logged into ColdFusion.
The user is logged in if the cfloginuser tag has run successfully for this application and the user has not been
logged out.
4 Code in the cflogin tag body uses the user ID and password from the browser login, contained in the cflogin.name
and cflogin.password variables, as follows. (With Digest or NTLM web server authentication, the cflogin.password
variable is the empty string.)
a It checks the users name against information it maintains about users and roles. In a simple case, the application
has two roles, one for users and one for administrators. The CFML assigns the Admin role to any user logged
on with the user ID Admin and assigns the User role to all other users.
b It calls the cfloginuser tag with the users ID, password, and roles, to identify the user to ColdFusion.
5 Application.cfc or the Application.cfm page completes processing, and ColdFusion processes the requested
application page.
6 The application uses the IsUserInAnyRole function to check whether the user belongs to a role before it runs
personalization. It can also use the ID as a database key to get user-specific data.
Important: If you use web serverbased authentication or any form authentication that uses a Basic HTTP
Authorization header, the browser continues to send the authentication information to your application until the user
closes the browser, or in some cases, all open browser windows. As a result, after the user logs out and your application
uses the cflogout tag, until the browser closes, the cflogin structure in the cflogin tag will contain the logged-out users
UserID and password. If a user logs out and does not close the browser, another user can access pages with the first users
login.
350
2 Code in the cflogin tag body checks to see if it has received a user ID and password, normally from a login form.
3 If there is no user ID or password, the code in the cflogin tag body displays a login form that asks for the users
ID and password.
The form posts the login information back to the originally requested page, and the cflogin tag in the
onRequestStart method or the Application.cfm page runs again. This time, the cflogin tag body code checks the
user name and password against a database, LDAP directory, or other policy store, to ensure that the user is valid
and get the users roles.
4 If the user name and password are valid, the cflogin tag body code calls the cfloginuser tag with the users ID,
to a role before they run protected code that must be available only to users in that role.
The application can use the GetAuthUser function to determine the user ID; for example, to display the ID for
personalization. It can also use the ID as a database key to get user-specific data.
6 Each application page displays a link to a logout form that uses the cflogout tag to log out the user. Typically, the
logout link is in a page header that appears in all pages. The logout form can also be in the Application.cfc (for
example, in the onRequestStart or onRequestEnd method) or on the Application.cfm page.
Although this scenario shows one method for implementing user security, it is only an example. For example, your
application could require users to log in for only some pages, such as pages in a folder that contains administrative
functions. When you design your user security implementation, remember the following:
Code in the cflogin tag body executes only if there is no user logged in.
With application authentication, you write the code that gets the identification from the user and tests this
information against a secure credential store.
After you have authenticated the user, you use the cfloginuser tag to log the user into ColdFusion.
351
The following image shows this flow of control. For simplicity, it omits the log-out option.
Step 1
User requests a
page.
Applicaton.cfc or
Application .cfm runs
first.
In Application.cfc
(or Application.cfm)
and related files
Form posts to
originally
requested
page.
Is a user
logged in?
Yes
Step 3
No
In cflogin tag
Step 2
User submits
form.
Display
login
form.
No
Yes
Step 4
Use ID and password to
request user's roles from
login database.
Is the user
valid?
No
Yes
In requested page
IsUserInRole
function
User is valid but
not authorized; do
not do secured
operations.
Step 5
Is user in role
needed for activity?
352
Simple Specify a single user ID and password in the wizard. All users must enter this information to log in. Use
this option for testing, or use the generated files as a template where you can replace the authentication code with
more complex code. For example, to verify the ID and password against a database.
NT domain Specify an NT domain in the wizard, and the wizard generates code that queries the domain.
LDAP Specify the LDAP server and port, the user name and password required to access the login data, and the
distinguished name to use to start the search for the user name. The wizard generates the code to query the LDAP
server with the user ID and password.
The wizard asks you to select one of the following options for displaying the request for login information:
Note: If the wizard creates the Application.cfc file, change the file to specify the application name. For more information
on Application.cfc, see Designing and Optimizing a ColdFusion Application on page 235.
mm_wizard_application_include.cfm The Login Wizard uses the information specified in the wizard fields to set
several CFC method arguments. It then uses them to invoke the performlogin method of the master login CFC,
mm_wizard.authenticate.
mm_wizard_authenticate.cfc This CFC contains all of the user authentication and login logic. The CFC consists of the
following methods:
The ntauth, ldapauth, and simpleauth authentication methods check the users name and ID against the valid login
information, and return information about whether the user is authenticated. For the details of how they
authenticate the user and the specific return values, see the methods.
The performLogin method is the master login method. It contains the cflogin tag, which displays the login form
and calls the required authentication method. If the authentication methods return argument indicates a valid
user, the method logs the user in.
The logout method logs out a user. If you specified Browser Dialog Box as the login page type, it also calls the
closeBrowser method to close the browser window. This behavior is necessary because the browser continues to
send the old login credentials after the user logs out, and the cflogin tag will automatically use them and log the
user in again.
The closeBrowser method closes the browser window or tells the user to close the browser window to complete the
logout, depending on the browser type.
353
mm_wizard_login.cfm This file contains a ColdFusion login form. The wizard generates this file for all options, but
otherwise, creates an mm_wizard_index.cfm page. These pages let you test the generated login code before you
implement your application, or without using any of your standard application pages. To test your login, open the
index.cfm page in your browser.
Modifying the login code for your application
The Login Wizard creates a basic framework for authenticating a user. Customize this framework to meet the needs
of your application. Typical security-related changes include the following:
354
Note: For greater security, consider using a hashed password. Do not store the password directly in the database; instead,
use the hash function to create a secure password fingerprint, and store it in the database. When the user provides a
password, use the Hash function on the submitted string and compare it with the value in the database.
This simple example does not provide a user log-out interface. Test the security behavior by adding your own pages to
the same directory as the Application.cfc page.
Example: Application.cfc
The Application.cfc page consists of the following:
355
<cfcomponent>
<cfset This.name = "Orders">
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<cflogin>
<cfif IsDefined("cflogin")>
<cfif cflogin.name eq "admin">
<cfset roles = "user,admin">
<cfelse>
<cfset roles = "user">
</cfif>
<cfloginuser name = "#cflogin.name#" password = "#cflogin.password#"
roles = "#roles#" />
<cfelse>
<!--- This should never happen. --->
<h4>Authentication data is missing.</h4>
Try to reload the page or contact the site administrator.
<cfabort>
</cfif>
</cflogin>
</cffunction>
</cfcomponent>
Description
<cfcomponent>
<cfset This.name = "Orders">
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<cflogin>
<cfif IsDefined("cflogin")>
<cfif cflogin.name eq "admin">
<cfset roles = "user,admin">
<cfelse>
<cfset roles = "user">
</cfif>
Logs the user into the ColdFusion security system and specifies the users
password, name, and roles. Gets the password and name directly from the
cflogin structure.
<cfelse>
<!--- This should never happen. --->
<h4>Authentication data is missing.</h4>
Try to reload the page or contact the site
administrator.
<cfabort>
This code should never run, but if the user somehow got to this page
without logging in to the web server, this message would display and
ColdFusion would stop processing the request.
</cfif>
</cflogin>
</cffunction>
</cfcomponent>
Makes sure that the user is correctly logged in by the web server.
(Otherwise, there would be no cflogin variable.)
Sets a roles variable based on the users ID. Assigns users named "admin"
to the admin role. Assigns all other users to the users role.
356
Example: securitytest.cfm
The securitytest.cfm page shows how any application page uses ColdFusion user authorization features. The web
server ensures the existence of an authenticated user, and the Application.cfc page ensures that the user is assigned to
roles the page content appears. The securitytest.cfm page uses the IsUserInAnyRole and GetAuthUser functions to
control the information that is displayed.
The securitytest.cfm page consists of the following:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Basic authentication security test page</title>
</head>
<body>
<cfoutput>
<h2>Welcome #GetAuthUser()#!</h2>
</cfoutput>
ALL Logged-in Users see this message.<br>
<br>
<cfscript>
if (IsUserInRole("admin"))
WriteOutput("Users in the admin role see this message.<br><br>");
if (IsUserInRole("user"))
WriteOutput("Everyone in the user role sees this message.<br><br>");
</cfscript>
</body>
</html>
Description
<cfoutput>
<h2>Welcome #GetAuthUser()#!</h2>
</cfoutput>
Displays this message in all cases. The page does not display until a
user is logged in.
<cfscript>
if (IsUserInRole("admin"))
WriteOutput("Users in the admin role see this
message.<br><br>");
if (IsUserInRole("user"))
WriteOutput("Everyone in the user role sees this
message.<br><br>");
</cfscript>
Tests whether the user belongs to each of the valid roles. If the user is
in a role, displays a message with the role name.
The user sees one message per role to which the user belongs.
357
The Application.cfc page contains the authentication logic that checks whether a user is logged in, requests the
login page if the user is not logged in, and authenticates the data from the login page. If the user is authenticated, it
logs the user in.
This page also includes the one-button form and logic for logging out a user, which appears at the top of each page.
The loginform.cfm page displays the login form. The code on this page could also be included in Application.cfc.
The securitytest.cfm page is a sample application page. It displays the logged-in users roles.
Test the security behavior by adding your own pages to the same directory as the Application.cfc page.
The example gets user information from the LoginInfo table of the cfdocexamples database that is installed with
ColdFusion. You can replace this database with any database containing UserID, Password, and Roles fields. The
sample database contains the following data:
UserID
Password
Roles
BobZ
Ads10
Employee,Sales
JaniceF
Qwer12
Contractor,Documentation
RandalQ
ImMe
Employee,Human Resources,Manager
Because spaces are meaningful in roles strings, do not follow the comma separators in the Roles fields with spaces.
Example: Application.cfc
The Application.cfc page consists of the following:
<cfcomponent>
<cfset This.name = "Orders">
<cfset This.Sessionmanagement="True">
<cfset This.loginstorage="session">
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<cfif IsDefined("Form.logout")>
<cflogout>
</cfif>
<cflogin>
<cfif NOT IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<cfif cflogin.name IS "" OR cflogin.password IS "">
<cfoutput>
<h2>You must enter text in both the User Name and Password fields.
</h2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<cfquery name="loginQuery" dataSource="cfdocexamples">
SELECT UserID, Roles
FROM LoginInfo
WHERE
358
UserID = '#cflogin.name#'
AND Password = '#cflogin.password#'
</cfquery>
<cfif loginQuery.Roles NEQ "">
<cfloginuser name="#cflogin.name#" Password = "#cflogin.password#"
roles="#loginQuery.Roles#">
<cfelse>
<cfoutput>
<H2>Your login information is not valid.<br>
Please Try again</H2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
</cfif>
</cfif>
</cfif>
</cflogin>
<cfif GetAuthUser() NEQ "">
<cfoutput>
<form action="securitytest.cfm" method="Post">
<input type="submit" Name="Logout" value="Logout">
</form>
</cfoutput>
</cfif>
</cffunction>
</cfcomponent>
Description
<cfcomponent>
<cfset This.name = "Orders">
<cfset This.Sessionmanagement="True">
<cfset This.loginstorage="session">
<cffunction name="OnRequestStart">
<cfargument name = "request" required="true"/>
<cfif IsDefined("Form.logout")>
<cflogout>
</cfif>
If the user just submitted the logout form, logs out the user. The
following cflogin tag runs as a result.
<cflogin>
<cfif NOT IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
359
Code
Description
<cfelse>
<cfif cflogin.name IS "" OR cflogin.password IS "">
<cfoutput>
<h2>You must enter text in both the User Name and
Password fields. </h2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<cfquery name="loginQuery"
dataSource="cfdocexamples">
SELECT UserID, Roles
FROM LoginInfo
WHERE
UserID = '#cflogin.name#'
AND Password = '#cflogin.password#'
</cfquery>
Runs if the user submitted a login form and both fields contain data.
If the query returns data in the Roles field, logs in the user using the
users name and password and the Roles field from the database. In
this application, every user must be in some role.
<cfelse>
<cfoutput>
<H2>Your login information is not valid.<br>
Please Try again</H2>
</cfoutput>
<cfinclude template="loginform.cfm">
<cfabort>
Runs if the query did not return a role. If the database is valid, this
means there was no entry matching the user ID and password.
Displays a message, followed by the login form.
</cfif>
</cfif>
</cfif>
</cflogin>
Tests to make sure that both name and password have data. If either
variable is empty, displays a message, followed by the login form.
The cfabort tag prevents processing of any code that follows on this
page.
Uses the cflogin structures name and password entries to find the
user record in the database and get the users roles.
The cfabort tag prevents processing of any code that follows on this
page.
</cffunction>
</cfcomponent>
If the user clicks the button, posts the form to the applications
(theoretical) entry page, index.cfm.
Application.cfc then logs out the user and displays the login form. If
the user logs in again, ColdFusion displays index.cfm.
Example: loginform.cfm
The loginform.cfm page consists of the following:
360
Description
The form requests a user ID and password and posts the users input to
the page specified by the newurl variable.
Uses the field names j_username and j_password. ColdFusion
automatically puts form fields with these values in the cflogin.name
and cflogin.password variables inside the cflogin tag.
Example: securitytest.cfm
The securitytest.cfm page shows how any application page can use ColdFusion user authorization features.
Application.cfc ensures the existence of an authenticated user before the page content appears. The securitytest.cfm
page uses the IsUserInAnyRole and GetAuthUser functions to control the information that is displayed.
The securitytest.cfm page consists of the following:
361
Description
<cfoutput>
<h2>Welcome #GetAuthUser()#!</h2>
</cfoutput>
Displays this message in all cases. The page does not display until a
user is logged in.
<cfscript>
if (IsUserInRole("Human Resources"))
WriteOutput("Human Resources members see this
message.<br><br>");
if (IsUserInRole("Documentation"))
WriteOutput("Documentation members see this
message.<br><br>");
if (IsUserInRole("Sales"))
WriteOutput("Sales members see this
message.<br><br>");
if (IsUserInRole("Manager"))
WriteOutput("Managers see this message.<br><br>");
if (IsUserInRole("Employee"))
WriteOutput("Employees see this message.<br><br>");
if (IsUserInRole("Contractor"))
WriteOutput("Contractors see this
message.<br><br>");
</cfscript>
Tests whether the user belongs to each of the valid roles. If the user is
in a role, displays a message with the role name.
Users see one message per role that they belong.
362
363
#cflogin.name#")</script>
</cfoutput>
<cfabort>
<cfelse>
<cfoutput>
<script>alert("Unknown error for user: #cflogin.name#
#cfcatch.detail#")</script>
</cfoutput>
<cfabort>
</cfif>
</cfcatch>
</cftry>
<!--- If the LDAP query returned a record, the user is valid. --->
<cfif auth.recordcount>
<cfloginuser name="#cflogin.name#" password="#cflogin.password#"
roles="#valueList(auth.cn)#">
</cfif>
</cfif>
</cflogin>
364
Code
Description
<cflogin>
<cfif isDefined("cflogin")>
<!--- setting basic attributes --->
<cfset LDAP_root = "o=mycompany.com">
<cfset LDAP_server = "ldap.mycompany.com">
<cfset LDAP_port = "389">
Starts the cflogin tag body. Sets several variables to the values used as
attributes in the cfldap tag.
Sets prefix and suffix values used to create a distinquished name (dn) for
binding to the LDAP server.
Creates the users bind dn by concatenating the prefix and suffix with
cflogin.name. This variable is used for authenticating the user to the LDAP
server.
Sets the filter used to search the directory and retrieve the users group
memberships. The group membership represents the users roles within the
organization.
<cftry>
<cfldap action="QUERY"
name="auth"
attributes="cn"
referral="yes"
start="#LDAP_root#"
scope="SUBTREE"
server="#LDAP_server#"
port="#LDAP_port#"
filter="#userfilter#"
username="#LDAP_username#"
password="#cflogin.password#"
>
<cfcatch type="any">
<cfif FindNoCase("Invalid credentials",
cfcatch.detail)>
<cfoutput>
<script>alert("User ID or Password invalid for
user: #cflogin.name#")</script>
</cfoutput>
<cfabort>
<cfelse>
<cfoutput>
<script>alert("Unknown error for user:
#cflogin.name# #cfcatch.detail#")</script>
</cfoutput>
<cfabort>
</cfif>
</cfcatch>
</cftry>
<cfif auth.recordcount>
<cfloginuser name="#cflogin.name#"
password="#cflogin.password#"
roles="#valueList(auth.cn)#">
</cfif>
</cfif>
</cflogin>
If the authorization query returns a valid record, logs in the user. Uses the
valueList function to create a comma-separated list of the users retrieved
group memberships, and passes them in the cfloginuserroles attribute.
Note: The LDAP permissions must allow an authenticated user to read and
search groups in order for the query to return results.
Tests to see if the error information includes the string "invalid credentials",
which indicates that either the dn or password is invalid. If so, displays a
dialog box with an error message indicating the problem.
Otherwise, displays a general error message.
If an error is caught, the cfabort tag ends processing of the request after
displaying the error description.
End of cfcatch and cftry blocks.
365
Introduction to globalization
Globalization lets you create applications for all of your customers in all the languages that you support. In some cases,
globalization can let you accept data input using a different character set than the one you used to implement your
application. For example, you can create a website in English that lets customers submit form data in Japanese. Or, you
can allow a request URL to contain parameter values entered in Korean.
Your application also can process data containing numeric values, dates, currencies, and times. Each of these types of
data can be formatted differently for different countries and regions.
You can also develop applications in languages other than English. For example, you can develop your application in
Japanese so that the default character encoding is Shift-JIS, your ColdFusion pages contain Japanese characters, and
your interface displays in Japanese.
Globalizing your application requires that you perform one or more of the following actions:
Defining globalization
You might probably find several different definitions for globalization. Here, globalization is defined as an
architectural process where you place as much application functionality as possible into a foundation that can be
shared among multiple languages.
Globalization is composed of the following two parts:
Internationalization Developing language-neutral application functionality that can recognize, process, and respond
to data regardless of its representation. That is, whatever the application can do in one language, it can also do in
another. For example, think of copying and pasting text. A copy and paste operation should not be concerned with the
language of the text it operates on. For a ColdFusion application, you might have processing logic that performs
numeric calculations, queries a database, or performs other operations, independent of language.
Localization Taking shared, language-neutral functionality, and applying a locale-specific interface to it. Sometimes
this interface is referred to as a skin. For example, you can develop a set of menus, buttons, and dialog boxes for a
specific language, such as Japanese, that represents the language-specific interface. You then combine this interface
with the language-neutral functionality of the underlying application. As part of localization, you create the
functionality to handle input from customers in a language-specific manner and respond with appropriate responses
for that language.
366
Your website can also accept customer feedback or some other form of text input. You might want to support that
feedback in multiple languages using a variety of character sets.
367
You use Japanese encodings, such as Shift-JIS, EUC-JP, and ISO-2022-JP, to represent Japanese text. These encodings
can vary slightly, but they include a common set of approximately 10,000 characters used in Japanese.
The following terms apply to character encodings:
SBCS Single-byte character set; a character set encoded in one byte per character, such as ASCII or ISO 8859-1.
DBCS Double-byte character set; a method of encoding a character set in no more than 2 bytes, such as Shift-JIS. Many
character encoding schemes that are referred to as double-byte, including Shift-JIS, allow mixing of single-byte and
double-byte encoded characters. Others, such as UCS-2, use 2 bytes for all characters.
MBCS Multiple-byte character set; a character set encoded with a variable number of bytes per character, such as UTF-8.
The following table lists some common character encodings; however, there are many additional character encodings
that browsers and web servers support:
Encoding
Type
Description
ASCII
SBCS
Latin-1
SBCS
DBCS
(ISO 8859-1)
Shift_JIS
Note: Use an underscore character (_), not a hyphen (-) in the name in CFML attributes.
EUC-KR
DBCS
UCS-2
DBCS
UTF-8
MBCS
Multibyte Unicode encoding. ASCII is 7-bit; non-ASCII characters used in European and many
Middle Eastern languages are two-byte; and most Asian characters are three-byte
The World Wide Web Consortium maintains a list of all character encodings supported by the Internet. You can find
this information at www.w3.org/International/O-charset.html.
Computers must often convert between character encodings. In particular, the character encodings most commonly
used on the Internet are not used by Java or Windows. Character sets used on the Internet are typically single-byte or
multiple-byte (including DBCS character sets that allow single-byte characters). These character sets are most efficient
for transmitting data, because each character takes up the minimum necessary number of bytes. Currently, Latin
characters are most frequently used on the web, and most character encodings used on the web represent those
characters in a single byte.
Computers, however, process data most efficiently if each character occupies the same number of bytes. Therefore,
Windows and Java both use double-byte encoding for internal processing.
368
By default, ColdFusion uses UTF-8 to represent text data sent to a browser. UTF-8 represents the Unicode character
set using a variable-length encoding. ASCII characters are sent using a single byte. Most European and Middle Eastern
characters are sent as 2 bytes, and Japanese, Korean, and Chinese characters are sent as 3 bytes. One advantage of UTF8 is that it sends ASCII character set data in a form that is recognized by systems designed to process only single-byte
ASCII characters, while it is flexible enough to handle multiple-byte character representations.
While the default format of text data returned by ColdFusion is UTF-8, you can have ColdFusion return a page to any
character set supported by Java. For example, you can return text using the Japanese language Shift-JIS character set.
Similarly, ColdFusion can handle data that is in many different character sets. For more information, see Determining
the page encoding of server output on page 371.
Locales
A locale identifies the exact language and cultural settings to use for a user. The locale controls how to format the
following:
Dates
Times
Numbers
Currency amounts
ColdFusion supports all locales supported by the JVM that it uses.
Note: Current JVM versions (through 1.4.2) do not support localized numbers such as Arabic-hindic numbers used in
Arabic locales or hindic digits used in Hindi locales. ColdFusion uses Arabic numbers in all locales.
Locale names
ColdFusion supports two formats for specifying locale names: the standard Java locale names and the ColdFusion
naming convention that was required through ColdFusion 6.1.
You can specify all locales using a name consisting of the following:
Two lowercase letters to identify the language; for example, en for English, or zh for Chinese.
Optionally, an underscore and two uppercase letters to identify the regional variant of the language; for example,
US for the United States, or HK for Hong Kong.
369
For example, en_US represents United States English and es_MX represents Mexican Spanish. For a list of the
Java locale identifiers supported in the Sun 1.4.2 JVM and their meanings, see
http://java.sun.com/j2se/1.4.2/docs/guide/intl/locale.doc.html.
Previous to ColdFusion MX 7, ColdFusion supported a limited set of locales, and used identifiers that consisted of the
name of the language, followed, for most languages, by a regional identifier in parentheses, such as English (US) or
German (Standard). ColdFusion continues to support these names; for a list, see SetLocale in the CFML Reference.
The Server.coldfusion.supportedlocales variable is a comma-delimited list of the locale names that you can
specify.
ColdFusion also includes a GetLocaleDisplayName function that returns a locale name in a format that is meaningful
to users. It lets you display the locale using words in the users language; for example, franais (France).
By default, ColdFusion uses the JVM locale, and the default JVM locale is the operating system locale. You can set
the JVM locale value explicitly in ColdFusion in the JVM Arguments field on the Java and JVM Settings page in the
ColdFusion Administrator; for example:
-Duser.language=de -Duser.country=DE.
A locale set using the SetLocale function persists for the current request or until it is reset by another SetLocale
function in the request.
If a request has multiple SetLocale functions, the current locale setting affects how locale-sensitive ColdFusion
tags and functions (such as the functions that start with LS) format data. The last SetLocale function that
ColdFusion processes before sending a response to the requestor (typically the client browser) determines the value
of the response Content-Language HTTP header. The browser that requested the page displays the response
according to the rules for the language specified by the Content-Language header.
When ColdFusion formats date, time, currency, or numeric output, it determines how to format the output. You
can change the locale multiple times on a ColdFusion page to format information according to different locale
conventions. This enables you to output a page that properly formats different currency values, for example.
When ColdFusion returns a page to the client, it includes the HTTP Content-Language header. ColdFusion uses
the last locale setting on the page for this information.
Note: In earlier versions of ColdFusion, the default locale was always English, not the operating systems locale. For the
Japanese version of ColdFusion, the default was Japanese.
The following example uses the LSCurrencyFormat function to output the value 100,000 in monetary units for all the
ColdFusion-supported locales. You can run this code to see how the locale affects the data returned to a browser.
370
This example uses the ColdFusion variable Server.Coldfusion.SupportedLocales, which contains a list of all
supported ColdFusion locales.
BOM signature
UTF-8
EF BB BF
FE FF
FF FE
To insert a BOM character in a CFML page easily, your editor must support BOM characters. Many web page
development tools support insertion of these characters, including Dreamweaver, which automatically sets the BOM
based on the Page Properties Document Encoding selection.
371
If your page does not contain a BOM, you can use the cfprocessingdirective tag to set the character encoding of
the page. If you insert the cfprocessingdirective tag on a page that has a BOM, the information specified by the
cfprocessingdirective tag must be the same as for the BOM; otherwise, ColdFusion issues an error.
The following procedure describes how ColdFusion recognizes the encoding format of a ColdFusion page.
Determine the page encoding (performed by ColdFusion)
1 Use the BOM, if specified on the page.
Adobe recommends that you use BOM characters in your files.
2 Use the pageEncoding attribute of the cfprocessingdirective tag, if specified. For detailed information on how
to use this attribute, see the cfprocessingdirective tag in the CFML Reference.
3 Default to the JVM default file character encoding. By default, this is the operating system default character
encoding.
In this example, the response still uses the UTF-8 character set. Use the cfcontent tag to set the output character set.
However, within a ColdFusion page you can use the cfcontent tag to override the default character encoding of the
response. Use the type attribute of the cfcontent tag to specify the MIME type of the page output, including the
character set, as follows:
<cfcontent type="text/html charset=EUC-JP">
Note: ColdFusion also provides attributes that let you specify the encoding of specific elements, such as HTTP requests,
request headers, files, and mail messages. For more information, see Tags and functions for controlling character
encoding on page 372 and Handling data in ColdFusion on page 374.
The rest of this chapter describes ColdFusion tags and functions that you use for globalization, and discusses specific
globalization issues.
372
Attribute or parameter
Use
cfcontent
type
Specifies the encoding in which to return the results to the client browser.
For more information, see Determining the page encoding of server
output on page 371.
cffile
charset
cfheader
charset
cfhttp
charset
cfhttpparam
mimeType
Specifies the MIME media type of a file; can positionally include the files
character encoding.
cfmail
charset
cfmailpart
charset
cfprocessingdirective
pageEncoding
CharsetDecode
encoding
CharsetEncode
encoding
GetEncoding
SetEncoding
charset
Specifies the character encoding of text in the Form or URL scope. Used
when the character set of the input to a form, or the character set of a URL,
is not in UTF-8 encoding.
ToBase64
encoding
Specifies the character encoding of the string being converted to Base 64.
ToString
encoding
URLDecode
charset
URLEncodedFormat
charset
Use
GetLocale
GetLocaleDisplayName
Returns the name of a locale in the language of a specific locale. The default value is the current
locale in the locales language.
LSCurrencyFormat
Converts numbers into a string in a locale-specific currency format. For countries that use the euro,
the result depends on the JVM version.
LSDateFormat
Converts the date part of a date/time value into a string in a locale-specific date format.
373
Tag or function
Use
LSEuroCurrencyFormat
Converts a number into a string in a locale-specific currency format. Formats using the euro for all
countries that use euro as the currency.
LSIsCurrency
Determines whether a string is a valid representation of a currency amount in the current locale.
LSIsDate
Determines whether a string is a valid representation of a date/time value in the current locale.
LSIsNumeric
LSNumberFormat
LSParseCurrency
Converts a string that is a currency amount in the current locale into a formatted number. For
countries that use the euro, the result depends on the JVM version.
LSParseDateTime
Converts a string that is a valid date/time representation in the current locale into a date-time
object.
LSParseEuroCurrency
Converts a string that is a currency amount in the current locale into a formatted number. Requires
euro as the currency for all countries that use the euro.
LSParseNumber
Converts a string that is a valid numeric representation in the current locale into a formatted
number.
LSTimeFormat
Converts the time part of a date/time value into a string in a locale-specific date format.
SetLocale
Note: Many functions that have names starting with LS have corresponding functions that do not have this prefix:
DateFormat, IsDate, IsNumeric, NumberFormat, ParseDateTime, and TimeFormat. These function use English (US)
locale rules.
If you do not precede calls to the LS functions with a call to the SetLocale function, they use the locale defined by the
JVM, which typically is the locale of the operating system.
The following example uses the LSDateFormat function to display the current date in the format for each locale
supported by ColdFusion:
374
All string manipulation functions. For more information, see the String functions list in ColdFusion Functions in
the CFML Reference.
The GetTimeZoneInfo function, which returns the time zone of the operating system.
375
CORBA
Searching and indexing
Locale-specific content
Generating multilocale content
In an application that supports users in multiple locales and produces output that is specific to multiple locales, you
call the SetLocale function in every request to set the locale for that specific request. When processing has completed,
the locale should be set back to its previous value. One useful technique is to save the users desired locale in a Session
variable once the user has selected it, and use the Session variable value to set the locale for each user request during
the session.
Supporting the euro
The euro is the currency of many European countries, and ColdFusion supports the reading and writing of correctly
formatted euro values. Unlike other supported currencies, the euro is not tied to any single country (or locale). The
LSCurrencyFormat and LSParseCurrency functions rely on the underlying JVM for their operations, and the rules
used for currencies depend on the JVM. For Sun JVMs, the 1.3 releases did not support euros and used the older
country-specific currencies. The 1.4 releases use euros for all currencies that are in the euro zone as of 2002. If you are
using a JVM that does not support the euro, use the LSEuroCurrencyFormat and LSParseEuroCurrency functions
to format and parse euro values in locales that use euros as their currency.
376
One common method used to support non-ASCII characters within a URL is to include a name-value pair within the
URL that defines the character encoding of the URL. For example, the following URL uses a parameter called encoding
to define the character encoding of the URL parameters:
http://company.com/prod_page.cfm?name=Stephen;ID=7645;encoding=Latin-1
Within the prod_page.cfm page, you can check the value of the encoding parameter before processing any of the other
name-value pairs. This guarantees that you handle the parameters correctly.
You can also use the SetEncoding function to specify the character encoding of URL parameters. The SetEncoding
function takes two parameters: the first specifies a variable scope and the second specifies the character encoding used
by the scope. Since ColdFusion writes URL parameters to the URL scope, you specify "URL" as the scope parameter to
the function.
For example, if the URL parameters are passed using Shift-JIS, you could access them as follows:
<cfscript>
setEncoding("URL", "Shift_JIS");
writeoutput(URL.name);
writeoutput(URL.ID);
</cfscript>
Note: To specify the Shift-JIS character encoding, use the Shift_JIS attribute, with an underscore (_), not a hyphen (-).
Handling form data
The HTML form tag and the ColdFusion cfform tag let users enter text on a page, then submit that text to the server.
The form tags are designed to work only with single-byte character data. Since ColdFusion uses 2 bytes per character
when it stores strings, ColdFusion converts each byte of the form input into a two-byte representation.
However, if a user enters double-byte text into the form, the form interprets each byte as a single character, rather than
recognize that each character is 2 bytes. This corrupts the input text, as the following example shows:
1 A customer enters three double-byte characters in a form, represented by 6 bytes.
2 The form returns the six bytes to ColdFusion as six characters. ColdFusion converts them to a representation using
To work around this issue, use the SetEncoding function to specify the character encoding of input form text. The
SetEncoding function takes two parameters: the first specifies the variable scope and the second specifies the
character encoding used by the scope. Since ColdFusion writes form parameters to the Form scope, you specify "Form"
as the scope parameter to the function. If the input text is double-byte, ColdFusion preserves the two-byte
representation of the text.
The following example specifies that the form data contains Korean characters:
<cfscript>
setEncoding("FORM", "EUC-KR");
</cfscript>
<h1> Form Test Result </h1>
<strong>Form Values :</strong>
<cfset text = "String = #form.input1# , Length = #len(Trim(form.input1))#">
<cfoutput>#text#</cfoutput>
377
File data
You use the cffile tag to write to and read from text files. By default, the cffile tag assumes that the text that you are
reading, writing, copying, moving, or appending is in the JVM default file character encoding, which is typically the
system default character encoding. For cffile action="Read", ColdFusion also checks for a byte order mark (BOM)
at the start of the file; if there is one, it uses the character encoding that the BOM specifies.
Problems can arise if the file character encoding does not correspond to JVM character encoding, particularly if the
number of bytes used for characters in one encoding does not match the number of bytes used for characters in the
other encoding.
For example, assume that the JVM default file character encoding is ISO 8859-1, which uses a single byte for each
character, and the file uses Shift-JIS, which uses a two-byte representation for many characters. When reading the file,
the cffile tag treats each byte as an ISO 8859-1 character, and converts it into its corresponding two-byte Unicode
representation. Because the characters are in Shift-JIS, the conversion corrupts the data, converting each two-byte
Shift-JIS character into two Unicode characters.
To enable the cffile tag to correctly read and write text that is not encoded in the JVM default character encoding,
you can pass the charset attribute to it. Specify as a value the character encoding of the data to read or write, as the
following example shows:
<cffile action="read"
charset="EUC-KR"
file = "c:\web\message.txt"
variable = "Message" >
Databases
ColdFusion applications access databases using drivers for each of the supported database types. The conversion of
client native language data types to SQL data types is transparent and is done by the driver managers, database client,
or server. For example, the character data (SQL CHAR, VARCHAR) you use with JDBC API is represented using
Unicode-encoded strings.
Database administrators configure data sources and usually are required to specify the character encodings for
character column data. Many of the major vendors, such as Oracle, Sybase, and Informix, support storing character
data in many character encodings, including Unicode UTF-8 and UTF-16.
The database drivers supplied with ColdFusion correctly handle data conversions from the database native format to
the ColdFusion Unicode format. You do not have to perform any additional processing to access databases. However,
always check with your database administrator to determine how your database supports different character
encodings.
E-mail
ColdFusion sends e-mail messages using the cfmail, cfmailparam, and cfmailpart tags.
By default, ColdFusion sends mail in UTF-8 encoding. You can specify a different default encoding on the Mail page
in the ColdFusion Administrator, and you can use the charset attribute of the cfmail and cfmailpart tags to specify
the character encoding for a specific mail message or part of a multipart mail message.
HTTP
ColdFusion supports HTTP communication using the cfhttp and cfhttpparam tags and the GetHttpRequestData
function.
378
The cfhttp tag supports making HTTP requests. The cfhttp tag uses the Unicode UTF-8 encoding for passing data
by default, and you can use the charset attribute to specify the character encoding. You can also use the cfhttpparam
tag mimeType attribute to specify the MIME type and character set of a file.
LDAP
ColdFusion supports LDAP (Lightweight Directory Access Protocol) through the cfldap tag. LDAP uses the UTF-8
encoding format, so you can mix all retrieved data with other data and safely manipulated it. No extra processing is
required to support LDAP.
WDDX
ColdFusion supports the cfwddx tag. ColdFusion stores WDDX (Web Distributed Data Exchange) data as UTF-8
encoding, so it automatically supports double-byte character encodings. You do not have to perform any special
processing to handle double-byte characters with WDDX.
COM
ColdFusion supports COM through the cfobjecttype="com" tag. All string data used in COM interfaces is constructed
using wide characters (wchars), which support double-byte characters. You do not have to perform any special
processing to interface with COM objects.
CORBA
ColdFusion supports CORBA through the cfobjecttype="corba" tag. The CORBA 2.0 interface definition language
(IDL) basic type String used the Latin-1 character encoding, which used the full 8-bits (256) to represent characters.
As long as you are using CORBA later than version 2.0, which includes support for the IDL types wchar and wstring,
which map to Java types char and string respectively, you do not have to do anything to support double-byte
characters.
However, if you are using a version of CORBA that does not support wchar and wstring, the server uses char and string
data types, which assume a single-byte representation of text.
379
Description
Enables the display of the following information when ColdFusion displays the exception
error page. (Cleared by default.)
Enable Debugging
Line number and short snippet of the code where the error was identified
The classic.cfm template (the default) displays information as plain HTML text at the
bottom of the page.
The dockable.cfm template uses DHTML to display the debugging information using an
expanding tree format in a separate window. This window can be either a floating pane or
docked to the browser window. For more information on the dockable output format, see
Using the dockable.cfm output format on page 384.
Lists ColdFusion pages that run as the result of an HTTP request and displays execution
times, ColdFusion also highlights in red pages with processing times greater than the
specified value, and you can select between a summary display or a more detailed, tree
structured, display.
Displays general information about the request: ColdFusion Version, Template, Time Stamp,
User Locale, User Agent, User IP, and Host Name.
Database Activity
Displays debugging information about access to SQL data sources and stored procedures.
(Selected by default.)
Exception information
Lists all ColdFusion exceptions raised in processing the request. (Selected by default.)
Tracing information
Displays an entry for each cftrace tag. When this option is cleared, the debugging output
does not include tracing information, but the output page does include information for
cftrace tags that specify inline="Yes". (Selected by default.)
For more information on using the cftrace tag, see Using the cftrace tag to trace
execution on page 385.
380
Option
Description
Variables
Enables the display of ColdFusion variable values. When this option is cleared, disables
display of all ColdFusion variables in the debugging output. (Selected by default.)
When enabled, ColdFusion displays the values of variables in the selected scopes. You can
select to display the contents of any of the ColdFusion scopes except Variables, Attributes,
Caller, and ThisTag. To enhance security, Application, Server, and Request variable display is
disabled by default,
Enable CFSTAT
Enables you to use of the cfstat command line utility to monitor real-time performance.
This utility displays the same information that ColdFusion writes to the NT System Monitor,
without using the System Monitor application. For information on the cfstat utility, see
Configuring and Administering ColdFusion.
Description
ColdFusion
Template
The requested template. (In the dockable.cfm format, this appears in the Page Overview section and is called
Page.)
TimeStamp
The time the request was completed. (In the dockable.cfm format, this appears in the Page Overview section and
is called Date.)
Locale
The locality and language that determines how information is processed, particularly the message language.
381
Name
Description
User Agent
Remote IP
The IP address of the client system that made the HTTP request.
Host Name
The name of the host running the ColdFusion server that executed the request.
Execution Time
The Execution Time section displays the time required to process the request. It displays information about the time
required to process all pages required for the request, including the Application.cfc, Application.cfm, and
OnRequestEnd.cfm pages, if used, and any CFML custom tags, pages included by the cfinclude tag, and any
ColdFusion component (CFC) pages.
To display execution time for a specific block of code, use the cftimer tag.
You can display the execution time in two formats:
Summary
Tree
Note: Execution time decreases substantially between the first and second time you use a page after creating it or changing
it. The first time ColdFusion uses a page it compiles the page into Java bytecode, which the server saves and loads into
memory. Subsequent uses of unmodified pages do not require recompilation of the code, and therefore are substantially
faster.
Summary execution time format
The summary format displays one entry for each ColdFusion page processed during the request. If a page is processed
multiple times it appears only once in the summary. For example, if a custom tag gets called three time in a request, it
appears only once in the output.
The following table describes the display fields:
Column
Description
Total Time
The total time required to process all instances of the page and all pages that it uses. For example, if a request
causes a page to be processed two times, and the page includes another page, the total time includes the time
required to process both pages twice.
Avg Time
The average time for processing each instance of this page and the pages that it uses. The Avg Time multiplied
by the Count equals the Total Time.
Count
Template
382
The mytag2.cfm page was processed three times. All processing took 93 milliseconds, and the average processing
time was 31 milliseconds. (This page does not call any other pages.)
The mytag1.cfm page was processed two times. All processing took 78 milliseconds, and the average processing
time was 39 milliseconds. This time included the time to process mytag2.cfm (this tag calls the mytag2 custom tag);
therefore, the code directly on the page took an average of 8 milliseconds and a total of 16 milliseconds to process.
The includeme.cfm page took about 62 ms to process. This processing time includes the time to process the
mytag1.cfm, and therefore also the time to process mytag2.cfm once. Therefore the code directly on the page took
23 milliseconds (62-39) to process.
ColdFusion took 125 ms for processing that was not associated with a specific page.
The total processing time was 328 milliseconds, the sum of 125 + 203.
Database Activity
In the Administrator, when Database Activity is selected on the Debugging Settings page, the debugging output
includes information about database access.
SQL Queries
The SQL Queries section provides information about tags that generate SQL queries or result in retrieving a cached
database query: cfquery, cfinsert, cfgridupdate, and cfupdate.
The output displays the following information:
statement.
383
Stored Procedures
The stored procedures section displays information about the results of using the cfstoredproc tag to execute a
stored procedure in a database management system.
The output displays the following information:
A table listing the procedure result sets returned, as specified in the cfprocresult tag.
Exceptions
In the Administrator, when Exception Information is selected on the Debugging Settings page, the debugging output
includes a list of all ColdFusion exceptions raised in processing the application page.
The exception information includes information about any application exceptions that are caught and handled by
your application code or by ColdFusion.
Exceptions represent events that disrupt the normal flow of an application. You should catch and, whenever possible,
recover from foreseeable exceptions in your application, as described in Handling Errors on page 275. However, you
might also want to be alerted to caught exceptions when you are debugging your application. For example, if a file is
missing, your application can catch the cffile exception and use a backup or default file instead. If you enable
exception information in the debugging output, you can immediately see when this happens.
Trace points
In the Administrator, when Tracing Information is selected on the Debugging Settings page, the debugging output
includes the results of all cftrace tags, including all tags that display their results inline. Therefore, the debugging
output contains a historical record of all trace points encountered in processing the request.
For more information on using the cftrace tag, see Using the cftrace tag to trace execution on page 385.
Scope variables
In the Administrator, when the Variables option and one or more variable scopes are selected on the Debugging
Settings page, the debugging output displays the values of all variables in the selected scopes. The debugging output
displays the values that result after all processing of the current page.
By displaying selected scope variables you can determine the effects of processing on persistent scope variables, such
as application variables. This can help you locate problems that do not generate exceptions.
The Form, URL, and CGI scopes are useful for inspecting the state of a request. They let you inspect parameters that
affect page behavior, as follows:
URL variables Identify the HTTP request parameters.
Form variables Identify the form fields posted to an action page.
CGI variables Provide a view of the server environment following the request.
384
Similarly, the Client, Session, Application, and Server scope variables show the global state of the application, and can
be useful in tracing how each page affects the state of the ColdFusion persistent variables.
Description
Tells ColdFusion to display the debugging information for the selected frame. Refreshes the debug
pane if you select it for the current frame (or the application does not use frames).
Toggles the display between a floating window and a pane docked to the left of the selected frame.
You can expand and collapse each debugging information category, such as Exceptions, by clicking the plus or
minus sign (+ or -) in front of each category heading. You can also expand and collapse each scope data type display
in the Scoped Variables section.
The top of the debug pane displays the URL of the application page being debugged (as identified by the
cgi.script_name variable). Click this link to refresh the page and display the debugging information that results.
(You can also refresh the page and debugging information by using your browsers Refresh button or key.)
The debug pane also displays a box where you can enter a page path or URL. When you click the Go button,
ColdFusion processes the page and the debug pane is updated with the debugging information for the new page.
If Database Activity is selected in the Administrator, specify debug="No" to prevent ColdFusion from displaying
the querys SQL and statistics in the debugging output.
If Database Activity is not selected in the Administrator, specify debug="Yes" or debug to have ColdFusion display
the querys SQL and statistics in the debugging output.
For example, if Database Activity is not selected in the Administrator, you can use the following code to show the query
execution time, number of records returned, ColdFusion page, timestamp, and the SQL statement sent to the data
source for this query only:
<cfquery name="TestQuery" datasource="cfdocexamples" debug>
SELECT * FROM TestTable
</cfquery>
385
The debug attribute can be useful to disable query debugging information generated by queries in custom tags that
you call frequently, so that you only see the debugging information for queries in pages that call the tags.
You can also view stored procedure-specific debugging information by specifying the debug attribute in the
cfstoredproc tag.
You can put this tag in the initialization code of the Application.cfc file or on your Application.cfm page to suppress
all debugging output for an application, and override it on specific pages by setting showDebugOutput="Yes" in
cfsetting tags on those pages. Conversely, you can leave debugging on for the application, and use the cfsetting
showDebugOutput="No" tag to suppress debugging on individual pages where the output could cause errors or
confusion.
You can also use the showDebugOutput attribute to control debugging output if you do not have access to the
ColdFusion Administrator, but only if the Administrator enables debugging.
If you use cfdump tags frequently for debugging, place them in <cfif IsDebugMode()> tags; for example <cfif
IsDebugMode()><cfdump var=#myVar#></cfif>. This way you ensure that if you leave any cfdump tags in
production code, they are not displayed when you disable debugging output.
386
You can display the cftrace tag output in either or both of the following ways:
As a section in the debugging output: To display the trace information in the debugging output, in the
Administrator, select Tracing Information on the Debugging Settings page.
Inline in your application page: When you specify the inline attribute in a cftrace tag, ColdFusion displays the
trace output on the page at the cftrace tag location. (An inline cftrace tag does not display any output if it is
inside a cfsilent tag block.)
The cftrace tag executes only if you select Enable Debugging on the ColdFusion Administrator Debugging Settings
page. To display the trace results in the debugging output, you must also specify Tracing Information on the
Debugging Settings page; otherwise, the trace information is logged and inline traces are displayed, but no trace
information appears in the debugging output.
Note: When you use inline trace tags, ColdFusion sends the page to the browser after all page processing is completed, but
before it displays the debugging output from the debug template. As a result, if an error occurs after a trace tag but before
the end of the page, ColdFusion might not display the trace for that tag.
The following image shows inline trace messages:
387
Entry
Meaning
Trace type (severity) specified in the cftrace call; in this case,
Information.
[CFTRACE 13:21:11.011]
[501 ms]
Time taken for processing the current request to the point of the
cftrace tag.
[C:\CFusion\wwwroot\MYStuff\mydocs\tractest.cfm]
Path in the web server of the page that contains the cftrace tag.
@ line:14
[UDF End]
The cftrace tag text attribute with any variables replaced with their
values.
MyStatus Success
Name and value of the variable specified by the cftrace tag var
attribute.
ColdFusion logs all cftrace output to the file logs\cftrace.log in your ColdFusion installation directory.
A log file entry looks like the following:
"Information","web-29","04/01/02","13:21:11","MyApp","[501 ms (1st trace)]
[C:\ColdFusion9\wwwroot\MYStuff\mydocs\tractest.cfm @ line: 14] - [UDF End] [MyStatus =
Success] GetRecords UDF call has completed "
This entry is in standard ColdFusion log format, with comma-delimited fields inside double-quote characters. The
information displayed in the trace output is in the last, message, field.
The following table lists the contents of the trace message and the log entries. For more information on the log file
format, see Logging errors with the cflog tag on page 285.
Entry
Meaning
Information
web-29
04/01/02
13:21:11
MyApp
Path of the page on which the trace tag is located and the
line number of the cftrace tag on the page.
388
Entry
Meaning
[UDF End]
[MyStatus = Success]
Using tracing
As its name indicates, the cftrace tag is designed to help you trace the execution of your application. It can help you
do any of several things:
You can time the execution of a tag or code section. This capability is useful for tags and operations that can take
substantial processing time. Typical candidates include all ColdFusion tags that access external resources, including
cfquery, cfldap, cfftp, cffile, and so on. To time execution of any tag or code block, call the cftrace tag
before and after the code you want to time.
You can display the values of internal variables, including data structures. For example, you can display the raw
results of a database query.
You can display an intermediate value of a variable. For example, you could use this tag to display the contents of
a raw string value before you use string functions to select a substring or format it.
You can display and log processing progress. For example, you can place a cftrace call at the head of pages in your
application or before critical tags or calls to critical functions. (Doing this could result in massive log files in a
complex application, so use this technique with care.)
If a page has many nested cfif and cfelseif tags you can place cftrace tags in each conditional block to trace
the execution flow. When you do this, use the condition variable in the message or var attribute.
If you find that the ColdFusion server is hanging, and you suspect a particular block of code (or call to a cfx tag,
COM object, or other third-party component), you can place a cftrace tag before and after the suspect code, to
log entry and exit.
389
Attribute
Purpose
abort
A Boolean value. If you specify True, ColdFusion stops processing the current request immediately after the tag.
This attribute is the equivalent of placing a cfabort tag immediately after the cftrace tag. The default is False.
If this attribute is True, the output of the cftrace call appears only in the cftrace.log file. The line in the file
includes the text [ABORTED].
category
A text string specifying a user-defined trace type category. This attribute lets you identify or process multiple
trace lines by categories. For example, you could sort entries in a log according to the category.
The category attribute is designed to identify the general purpose of the trace point. For example, you might
identify the point where a custom tag returns processing to the calling page with a Custom Tag End category.
You can also use finer categories; for example, by identifying the specific custom tag name in the category.
You can include simple ColdFusion variables, but not arrays, structures, or objects, in the category text by
enclosing the variable name in number signs (#).
inline
A Boolean value. If you specify True, ColdFusion displays trace output in-line in the page. The default is False.
The inline attribute lets you display the trace results at the place that the cftrace call is processed. This
provides a visual cue directly in the ColdFusion page display.
Trace output also appears in a section in the debugging information display.
text
A text message describing this trace point. You can include simple ColdFusion variables, but not arrays,
structures, or objects, in the text output by enclosing the variable name in number signs (#).
type
A ColdFusion logging severity type. The inline trace display and dockable.cfm output format show a symbol for
each type. The default debugging output shows the type name, which is also used in the log file. The type name
must be one of the following:
Information (default)
Warning
Error
Fatal Information
var
The name of a single variable that you want displayed. This attribute can specify a simple variable, such as a string,
or a complex variable, such as a structure name. Do not surround the variable name in number signs.
Complex variables are displayed in inline output in cfdump format; the debugging display and log file report the
number of elements in the complex variable, instead of any values.
You can use this attribute to display an internal variable that the page does not normally show, or an intermediate
value of a variable before the page processes it further.
To display a function return value, place the function inside the message. Do not use the function in the var
attribute, because the attribute cannot evaluate functions.
Note: If you specify inline trace output, and a cftrace tag is inside a cfsilent tag block, ColdFusion does not display
the trace information in line, but does include it in the standard debugging display.
The following cftrace tag displays the information in the example output and log entry in About the cftrace tag on
page 386 :
<cftrace abort="False" category="UDF End" inline = "True" text = "GetRecords UDF
call has completed" var = "MyStatus">
390
Using timing
Use this tag to determine how long it takes for a block of code to execute. This is useful when ColdFusion debugging
output indicates excessive execution time, but does not pinpoint the long-running block of code.
To use this tag, enable debugging in the ColdFusion Administrator Debugging Settings page. In the Debugging
Settings page, you must also specifically enable usage of the cftimer tag by checking the Timer Information check box.
If you enable debugging for the cftimer tag only and display timing information in an HTML comment, you can
generate timing information without disturbing production users.
Comment: Displays timing information in an HTML comment in the format <!--label: elapsed-timems >--. The
default label is cftimer.
Debug: Displays timing information in the debugging output under the heading CFTimer Times.
The following example calls the cftimer tag multiple times, each time using a different type attribute:
<HTML>
<body>
<h1>CFTIMER test</h1>
<!--- type="inline" --->
<cftimer label="Query and Loop Time Inline" type="inline">
<cfquery name="empquery" datasource="cfdocexamples">
select *
from Employees
</cfquery>
<cfloop query="empquery">
<cfoutput>#lastname#, #firstname#</cfoutput><br>
</cfloop>
</cftimer>
<hr><br>
<!--- type="outline" --->
<cftimer label="Query and CFOUTPUT Time with Outline" type="outline">
<cfquery name="coursequery" datasource="cfdocexamples">
select *
from CourseList
</cfquery>
<table border="1" width="100%">
<cfoutput query="coursequery">
<tr>
<td>#Course_ID#</td>
<td>#CorName#</td>
<td>#CorLevel#</td>
</tr>
</cfoutput>
</table>
</cftimer>
<hr><br>
391
It can validate the CFML syntax of your application. To do so, the analyzer runs the ColdFusion compiler on your
pages, but does not execute the compiled code. It reports errors that the compiler encounters.
It provides information about the incompatibility (and its severity), and suggests a remedy where one is required.
It can identify places where ColdFusion might behave differently than previous versions. The analyzer identifies the
following kinds of features:
No longer supported: Their use results in errors. For example, the closable attribute is not supported for the tag
cflayoutarea in border layout (cflayout with type="border").
Deprecated: They are still available, but their use is not recommended and they might not be available in future
releases. Deprecated features might also behave differently now than in previous releases. For example, in
cfcache tag the following attributes are deprecated: directory, cachedirectory, port, and protocol.
Modified behavior: They might behave differently than in previous versions. For example, if you use cfcache
tag in ColdFusion 9 without end tag (</cfcache>), then instead of caching only the current page (which was
the behavior in the previous releases), the entire request is cached.
392
New: These are features newly added to ColdFusion 9. For example, if you use throw as a user-defined function
in a CFM, analyzer informs that throw is a built-in ColdFusion function and suggests you to rename. If you use
throw as a user-defined function in a CFC, analyzer informs that throw is a built-in function and suggests you
to prefix it with object scope. For more details on new features, see example, Whats new in ColdFusion 9 on
page 5.
You can run the Code Analyzer from the ColdFusion Administrator. Select Code Analyzer from the list of Debugging
& Logging pages.
Note: The Code analyzer does not execute the pages that it checks. Therefore, it cannot detect invalid attribute
combinations if the attribute values are provided dynamically at runtime.
These errors typically indicate that you have unbalanced <, ", or # characters. One of the most common coding errors
is to forget to close quoted code, number sign-delimited variable names, or opening tags. Make sure the code in the
identified line and previous lines do not have missing characters.
The line number in the error message often does not identify the line that causes the error. Instead, it identifies the
first line where the ColdFusion compiler encountered code that it could not handle as a result of the error.
Problem: You get an error message you do not understand.
Make sure all your CFML tags have matching end tags where appropriate. It is a common error to omit the end tag for
the cfquery, cfoutput, cftable, or cfif tag.
As with the previous problem, the line number in the error message often does not identify the line that causes the
error, but the first line where the ColdFusion compiler encounters code that it could not handle as a result of the error.
Whenever you have an error message that does not appear to report a line with an error, check the code that precedes
it for missing text.
Problem: Invalid attribute or value.
If you use an invalid attribute or attribute values, ColdFusion returns an error message. To prevent such syntax errors,
use the CFML Code Analyzer. Also see Using the cftrace tag to trace execution on page 385.
Problem: You suspect that there are problems with the structure or contents of a complex data variable, such as a
structure, array, query object, or WDDX-encoded variable.
Use the cfdump tag to generate a table-formatted display of the variables structure and contents. For example, to dump
a structure named relatives, use the following line. Surround the variable name with number signs (#).
393
<cfdump var=#relatives#>
HTTP/URL
Problem: ColdFusion cannot correctly decode the contents of your form submission.
The method attribute in forms sent to the ColdFusion server must be Post, for example:
<form action="test.cfm" method="Post">
Problem: The browser complains or does not send the full URL string when you include spaces in URL parameters.
Some browsers automatically replace spaces in URL parameters with the %20 escape sequence, but others might
display an error or just send the URL string up to the first character (as does Netscape 4.7).
URL strings cannot have embedded spaces. Use a plus sign (+) or the standard HTTP space character escape sequence
(%20), wherever you want to include a space. ColdFusion correctly translates these elements into a space.
A common scenario in which this error occurs is when you dynamically generate your URL from database text fields
that have embedded spaces. To avoid this problem, include only numeric values in the dynamically generated portion
of URLs.
Or, you can use the URLEncodedFormat function, which automatically replaces spaces with %20 escape sequences. For
more information on the URLEncodedFormat function, see the CFML Reference.
394
Setting breakpoints
Viewing variables
Stepping over, into, and out of function calls
Eclipse version 3.1.2, Eclipse version 3.2, Flex Builder 2, or Flash Builder
ColdFusion 9
To install the ColdFusion Debugger, you install the ColdFusion Eclipse plugins. For more information, see Installing
ColdFusion.
step 3. By default, ColdFusion launches the debugger server with a random available port. This could be a problem
if ColdFusion (and hence debugger server) is behind a firewall and the firewall blocks the random port that the
debugger is listening..
To prevent this problem, you can specify a fixed debugger server port number and allow this port in the firewall.
To set a fixed debugger server port number, specify the following JVM argument on the Java and JVM page of the
ColdFusion Administrator (or the appropriate place for you J2EE Application Server), replacing portNumber with
the port you want to use:
-DDEBUGGER_SERVER_PORT=portNumber
8 Restart ColdFusion. If you are running the J2EE configuration of ColdFusion, restart the server in debug mode with
395
9 To modify the debug settings, in Eclipse, select Window > Preferences > ColdFusion > Debug Settings. You can
specify the home page URL, which points to the page that appears in the Debug Output Buffer of the debugger when
you click the Home button. You can also specify the extensions of the types of files that you can debug and variable
scopes that you want the Debugger to recognize. To improve performance when debugging large files, deselect all
scopes for which you do not require information.
Note: To ensure that the debugger stops in the template you are debugging on the line that causes a ColdFusion error,
select Preferences > ColdFusion > Debug Settings and select the Enable Robust Exception Information checkbox.
10 To configure an RDS server, in Eclipse, select Window > Preferences > ColdFusion > RDS Configuration.
If you are running ColdFusion on the same computer as Eclipse, localhost is configured by default. To use any
additional RDS servers, enter the configuration information.
11 If ColdFusion and Eclipse are not running on the same computer, in Eclipse, select Window > Preferences >
ColdFusion > Debug Mappings. Then specify the path that Eclipse uses to open files on the ColdFusion server and
the path that ColdFusion uses to find the files that you are editing in Eclipse.
Mapping ensures that Eclipse and ColdFusion are working on the same file. For example, if you are editing files in
an Eclipse project that points to D:\MyCoolApp. Then, when you deploy the files to the ColdFusion server, you
copy them to W:\websites\MyCoolSite\, which the ColdFusion server recognizes as
D:\Shared\websites\MyCoolSite. The mapping in Eclipse specifies that the Eclipse directory is D:\MyCoolApp and
the server is D:\Shared\websites\MyCoolSite. Eclipse translates the file path (D:\MyCoolApp\index.cfm) to a path
that the ColdFusion server recognizes (D:\Shared\websites\MyCoolSite\index.cfm). To see more information
about the interaction between the client and the server, add the following to the JVM arguments in the ColdFusion
Administrator:
-DDEBUGGER_TRACE=true
12 If you are not running the server configuration of ColdFusion, specify Java debugging parameters in the
configuration file or startup script of the application server you are running. The parameters should look like the
following:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=<port_number>
Ensure that the port number you specify is the same port number specified on the Debugger Settings page of
ColdFusion Administrator.
If you are running the server configuration, ColdFusion writes these debugging parameters to the jvm.config file
when you use the Debugger Settings page of the ColdFusion Administrator.
13 If you are not running the server configuration and your application server is not running on JRE 1.6, copy the
tools.jar file of the JDK version that your application server is running to the \lib folder of ColdFusion. For example,
if you are running JRun that runs on JRE 1.4, copy the tools.jar file of JDK 1.4 to the \lib folder of ColdFusion.
14 If you are running the server version of ColdFusion and you specify a JRE version other than JRE 1.6 in the
jvm.config file, copy the tools.jar file of the JDK version specified in your jvm.config file to the \lib folder of
ColdFusion.
Note: To debug ColdFusion applications running on the multiserver configuration, start the ColdFusion server from the
command line using the following command:
jrun -config <path_to_jvm_config> -start <server_name>
396
You can modify RDS configurations easily from the RDS Fileview or RDS Dataview by clicking the Edit RDS
Preferences button in the view.
Debug pane, which keeps the results of each completed session. The following buttons appear at the top of this pane:
Resume - Resumes a debugging session
Suspend - Pauses a debugging session
Terminate - Stops a debugging session
Disconnect - Disconnects the debugger from the selected debug target when debugging remotely
Remove All Terminated Launches - Clears all terminated debug targets from the display
Step Into - Executes code line by line, including included code, UDFs, CFCs, and the like
Step Over - Executes code line by line, excluding included code, UDFs, CFCs, and the like
Step Return - Returns to the original page from which you entered the included code, UDF, CFC, or the like
Drop to Frame -Reenters a specified stack frame, which is analogous to going in reverse and restarting your
program partway through
Use Step Filters/Step Debug - Ensures that all step functions apply step filters
Menu - Displays the menu that lets you manage the view, show system threads, show qualified names, and show
monitors
Variables pane, which shows the current variables, including the variable scope. The following buttons appear at
the top of this pane:
Go to File for Breakpoint - Goes to the file in which the selected breakpoint is set
Skip All Breakpoints - Ignores all breakpoints
Expand All - Expands the information in the pane
Collapse All - Collapses the information in the pane
Link with Debug View - Highlights the selected breakpoint when the application stops execution in the Debug View
Add Java Exception Breakpoint - Lets you specify which Java exception to throw when you reach the selected
breakpoint
397
Menu - Lets you specify the type of information to display in the Breakpoints pane
Debug Output Buffer - Contains two panes: Browser, which displays what appears in the browser during
application execution; Server Output Buffer, which displays the debug output.
Edit pane, which displays the stacked source panes, one for each source file you have open.
Outline pane, which displays the current source files content in outline form
Setting a breakpoint
Executing code line by line
Inspecting variables
You do not have to create an Eclipse project in the same folder as CFML source. You can create a project in a
different folder, create a folder under that project, and then link it to the folder where CFML sources reside.
2 Click Debug in the upper-right corner of the Eclipse workbench to go to the Debug perspective.
3 Select Window > Show View > Debug Output Buffer to see the output from your application and how your
that you can debug, and the variable scopes of the variables to show in the Variables pane. Click OK.
The home page is the page that appears in the Debug Output Buffer pane when you click the Home button in the
Debug Output Buffer pane.
5 To begin debugging the file whose source appears in the Edit pane, click the Debug icon in the Eclipse toolbar.
6 Click New to create a new debugging configuration.
7 Specify the home page for the active debug session.
This is the page that appears in the Debug Output Buffer pane when you click the Debug Session Home button in
the Debug Output Buffer pane.
8 Click Debug to start the debug session.
Note: If you are in the process of debugging a template and then try to browse to or refresh that page, doing so can result
in unexpected behavior in the Debugger.
Setting a breakpoint
You can set breakpoints in your CFML file to stop execution of the page at particular points. When you set a
breakpoint on a line, execution of the CFML stops just before that line. For example, if you set a breakpoint on the
third line in the following CFML page, execution stops before <cfset myName = "Wilson">.
<cfset yourName = "Tuckerman">
<cfoutput>Your name is #yourName#.</cfoutput>
<cfset myName = "Wilson"
398
Run the page that you want to debug before setting any breakpoints to compile it before debugging it. This improves
performance during debugging. You cannot set a breakpoint in a file that is not part of a project.
1 In Eclipse, open the file in which you want to set a breakpoint.
2 While highlighting the line where you want to set the breakpoint, do one of the following:
Double-click in the marker bar that appears to the left of the editor area.
Right click, and then select Toggle Breakpoint.
Press Alt+Shift+B.
A blue dot appears before the line on which you set the breakpoint.
Also, you can view a list of breakpoints set in the current Eclipse project in the Breakpoints panel.
ColdFusion breakpoints have four states in the Eclipse debugger:
Enabled and Valid - This is a breakpoint at a valid location. It is represented by a solid blue circle and stops code
execution when encountered.
Unresolved - ColdFusion sets the breakpoint for the page that is loaded in its memory. If you modify the page
and do not execute it, the source is not in sync with the page that ColdFusion sees on the server. In this situation,
ColdFusion may consider the line where you want to set breakpoint to be invalid. However, you have not yet
executed the page; when you do so, that line may be valid. This type of breakpoint is represented by a question
mark (?) icon.
For performance reasons, ColdFusion does not try to resolve unresolved breakpoints every time you execute the
page. It tries to resolve them when you modify the page and execute it. If you think that the line at which
ColdFusion shows an unresolved breakpoint is valid, delete the breakpoint and set it again.
Invalid - If ColdFusion determines that the CFML that you edit in Eclipse is the same as the CFML in its
memory, and that the breakpoint you have set is at an invalid line, the breakpoint appears as a red X.
Disabled.
399
Inspecting variables
As you observe execution of your code, you can see the values and scope of variables in the Variables panel. The
Variables panel displays the scope and value of variables as the CFML code executes. Only variables whose scopes are
those you selected in the Preferences dialog box appear in the Variables pane.
400
What is a database?
A database defines a structure for storing information. Databases are typically organized into tables, which are
collections of related items. You can think of a table as a grid of columns and rows. ColdFusion works primarily with
relational databases, such as Oracle, DB2, and SQL Server.
The following image shows the basic layout of a database table:
B
A column defines one piece of data stored in all rows of the table. A row contains one item from each column in the
table.
For example, a table contains the ID, name, title, and other information for individuals employed by a company. Each
row, called a data record, corresponds to one employee. The value of a column within a record is referred to as a record
field.
The following image shows an example table, named employees, containing information about company employees:
401
EmpID
LastName
FirstName
Title
DeptID
Phone
Smith
John
Engineer
jsmith
x5833
Note: The SQL keywords and syntax are represented here as uppercase letters. Table and column names use mixed
uppercase and lowercase letters.
LastName
FirstName
Title
DeptID
Phone
Jones
Joe
Engineer
jjones
x5844
Davis
Ken
Manager
kdavis
x5854
Baker
Mary
Engineer
mbaker
x5876
Smith
John
Engineer
jsmith
x5833
Morris
Jane
Manager
jmorris
x5833
Employees table
402
EmpID
Street
City
State
Zip
4 Main St.
Newton
MA
02158
10 Oak Dr.
Newton
MA
02161
15 Main St.
Newton
MA
02158
56 Maple Ln.
Newton
MA
02160
25 Elm St.
Newton
MA
02160
Addresses tables
In this example, each table contains a column named EmpID. This column associates a row of the employees table with
a row in the addresses table.
For example, to obtain all information about an employee, you request a row from the employees table and the row
from the addresses table with the same value for EmpID.
One advantage of using multiple tables is that you can add tables containing new information without modifying the
structure of your existing tables. For example, to add payroll information, you add a new table to the database where
the first column contains the employees ID and the columns contain current salary, previous salary, bonus payment,
and 401(k) percent.
Also, an access to a small table is more efficient than an access to a large table. Therefore, if you update the street
address of an employee, you update only the addresses table, without having to access any other table in the database.
Database permissions
In many database environments, a database administrator defines the access privileges for users accessing the database,
usually through user name and password. When a person attempts to connect to a database, the database ensures that
the user name and password are valid and then imposes access requirements on the user.
Privileges can restrict user access so that a user can do the following:
Read data.
Read data and add rows.
Read data, add rows, modify existing tables.
In ColdFusion, you use the ColdFusion Administrator to define database connections, called data sources. As part of
defining these connections, you specify the user name and password used by ColdFusion to connect to the database.
The database can then control access based on this user name and password.
For more information on creating a data source, see Configuring and Administering ColdFusion.
Commit
Rollback
Transactions
403
A database commit occurs when you make a permanent change to a database. For example, when you write a new row
to a database, the write does not occur until the database commits the change.
Rollback is the process of undoing a change to a database. For example, if you write a new row to a table, you can
rollback the write up to the point where you commit the write. After the commit, you can no longer rollback the write.
Most databases support transactions where a transaction consists of one or more SQL statements. Within a
transaction, your SQL statements can read, modify, and write a database. You end a transaction by either committing
all your changes within the transaction or rolling back all of them.
Transactions can be useful when you have multiple writes to a database and want to make sure all writes occurred
without error before committing them. In this case, you wrap all writes within a single transaction and check for errors
after each write. If any write causes an error, rollback all of them. If all writes occur successfully, you commit the
transaction.
A bank might use a transaction to encapsulate a transfer from one account to another. For example, if you transfer
money from your savings account to your checking account, you do not want the bank to debit the balance of your
savings account unless it also credits your checking account. If the update to the checking account fails, the bank can
rollback the debit of the savings account as part of the transaction.
ColdFusion includes the cftransaction tag that lets you implement database transactions for controlling rollback
and commit. For more information, see the CFML Reference.
Each record should contain a unique identifier as the primary key such as an employee ID, a part number, or a
customer number. The primary key is typically the column used to maintain each record's unique identity among
the tables in a relational database. Databases allow you to use multiple columns for the primary key.
When you define a column, you define a SQL data type for the column, such as allowing only numeric values to be
entered in the salary column.
Assessing user needs and incorporating those needs in the database design is essential to a successful
implementation. A well-designed database accommodates the changing data needs within an organization.
The best way to familiarize yourself with the capabilities of your database product or database management system
(DBMS) is to review the product documentation.
Using SQL
The following information introduces SQL, describes basic SQL syntax, and contains examples of SQL statements. so
that you can begin to use ColdFusion. For complete SQL information, see the SQL reference that ships with your
database.
A query is a request to a database. The query can ask for information from the database, write new data to the database,
update existing information in the database, or delete records from the database.
Structured Query Language (SQL) is an ANSI/ISO standard programming language for writing database queries. All
databases supported by ColdFusion support SQL, and all ColdFusion tags that access a database let you pass SQL
statements to the tag.
404
SQL example
The most commonly used SQL statement in ColdFusion is the SELECT statement. The SELECT statement reads data
from a database and returns it to ColdFusion. For example, the following SQL statement reads all the records from the
employees table:
SELECT * FROM employees
You interpret this statement as "Select all rows from the table employees" where the wildcard symbol (*) corresponds
to all columns.
If you are using Dreamweaver MX 2004, Adobe Dreamweaver CS3, or HomeSite+, you can use the built-in query
builder to build SQL statements graphically by selecting the tables and records to retrieve.
In many cases, you do not want all rows from a table, but only a subset of rows. The next example returns all rows from
the employees table, where the value of the DeptID column for the row is 3:
SELECT * FROM employees WHERE DeptID=3
You interpret this statement as "Select all rows from the table employees where the DeptID is 3".
SQL also lets you specify the table columns to return. For example, instead of returning all columns in the table, you
can return a subset of columns:
SELECT LastName, FirstName FROM employees WHERE DeptID=3
You interpret this statement as "Select the columns FirstName and LastName from the table employees where the
DeptID is 3".
In addition to with reading data from a table, you can write data to a table using the SQL INSERT statement. The
following statement adds a new row to the employees table:
INSERT INTO employees(EmpID, LastName, Firstname) VALUES(51, 'Doe', 'John')
Description
SELECT
INSERT
UPDATE
DELETE
Statement clauses
Use the following keywords to refine SQL statements:
Keyword
Description
FROM
405
Keyword
Description
WHERE
ORDER BY
GROUP BY
Operators
The following basic operators specify conditions and perform logical and numeric functions:
Operator
Description
AND
OR
NOT
LIKE
IN
BETWEEN
Equal to
<>
Not equal to
<
Less than
>
Greater than
<=
>=
Addition
Subtraction
Division
Multiplication
However, many databases, especially UNIX databases, are case sensitive. Case sensitivity means that you must match
exactly the case of all column and table names in SQL queries.
For example, the following queries are not equivalent in a case-sensitive database:
SELECT LastName FROM EMPLOYEES
SELECT LASTNAME FROM employees
406
If you use a ColdFusion variable in your SQL expression, and the variable value is a string that contains single
quotes, place the variable in a PreserveSingleQuotes function to prevent ColdFusion from interpreting the
quotation marks. The following example shows this use:
<cfset List = "'Suisun', 'San Francisco', 'San Diego'">
<cfquery name = "GetCenters" datasource = "cfdocexamples">
SELECT Name, Address1, Address2, City, Phone
FROM Centers
WHERE City IN (#PreserveSingleQuotes(List)#)
</cfquery>
There is a lot more to SQL than what is covered here. It is a good idea to purchase one or several SQL guides for
reference.
To perform a successful query, the data source, columns, and tables that you reference must exist.
Some DBMS vendors use nonstandard SQL syntax (known as a dialect) in their products. ColdFusion does not
validate the SQL; it is passed on to the database for validation, so you are free to use any syntax that your database
supports. Check your DBMS documentation for nonstandard SQL usage.
The query returns a database table. Because the data returned to ColdFusion by a SELECT statement is in the form of
a database table, ColdFusion lets you write a SQL query on the returned results. This functionality is called query of
queries. For more information on query of queries, see Accessing and Retrieving Data on page 410.
The next example uses a SELECT statement to return only a specific set of columns from a table:
SELECT LastName, FirstName FROM employees WHERE DeptID=3
Filtering results
The SELECT statement lets you filter the results of a query to return only those records that meet specific criteria. For
example, if you want to access all database records for employees in department 3, you use the following query:
SELECT * FROM employees WHERE DeptID=3
407
You can combine multiple conditions using the WHERE clause. For example, the following example uses two
conditions:
SELECT * FROM employees WHERE DeptID=3 AND Title='Engineer'
Sorting results
By default, a database does not sort the records returned from a SQL query. In fact, you cannot guarantee that the
records returned from the same query are returned in the same order each time you run the query.
However, if you require records in a specific order, you can write your SQL statement to sort the records returned from
the database. To do so, you include an ORDER BY clause in the SQL statement.
For example, the following SQL statement returns the records of the table ordered by the LastName column:
SELECT * FROM employees ORDER BY LastName
You can combine multiple fields in the ORDER BY clause to perform additional sorting:
SELECT * FROM employees ORDER BY DepartmentID, LastName
This statement returns row ordered by department, then by last name within the department.
Returning a subset of columns
You want only a subset of columns returned from a database table, as in the following example, which returns only the
FirstName, LastName, and Phone columns. This example is useful if you are building a web page that shows the phone
numbers for all employees.
SELECT FirstName, LastName, Phone FROM employees
However, this query does not to return the table rows in alphabetical order. You can include an ORDER clause in the
SQL, as follows:
SELECT the FirstName, LastName, Phone
FROM employees
ORDER BY LastName, FirstName
The results returned by this query contains columns named EmpID, LastName, and MyEQ.
Accessing multiple tables
In a database, you can have multiple tables containing related information. You can extract information from multiple
tables as part of a query. In this case, you specify multiple table names in the SELECT statement, as follows:
SELECT LastName, FirstName, Street, City, State, Zip
FROM employees, addresses
WHERE employees.EmpID = addresses.EmpID
ORDER BY LastName, FirstName
This SELECT statement uses the EmpID field to connect the two tables. This query prefixes the EmpID column with
the table name. This is necessary because each table has a column named EmpID. Prefix a column name with its table
name if the column name appears in multiple tables.
408
In this case, you extract LastName and FirstName information from the employees table and Street, City, State, and
ZIP information from the addresses table. You can use output such as this is to generate mailing addresses for an
employee newsletter.
The results of a SELECT statement that references multiple tables is a single result table containing a join of the
information from corresponding rows. A join means information from two or more rows is combined to form a single
row of the result. In this case, the resultant recordset has the following structure:
LastName
FirstName
Street
City
State
Zip
What is interesting in this result is that even though you used the EmpID field to combine information from the two
tables, you did not include that field in the output.
Modifying a database
You can use SQL to modify a database in the following ways:
Inserting data into a database
You use SQL INSERT statement to write information to a database. A write adds a new row to a database table. The
basic syntax of an INSERT statement is as follows:
INSERT INTO table_name(column_names) VALUES(value_list)
where:
This statement creates a row in the employees table and sets the values of the EmpID, LastName, and FirstName fields
of the row. The remaining fields in the row are set to Null. Nullmeans that the field does not contain a value.
When you, or your database administrator, creates a table, you can set properties on the table and the columns of the
table. One of the properties you can set for a column is whether the field supports Null values. If a field supports Nulls,
you can omit the field from the INSERT statement. The database automatically sets the field to Null when you insert
a new row.
409
However, if the field does not support Nulls, specify a value for the field as part of the INSERT statement; otherwise,
the database issues an error.
The LastName and FirstName values in the query are contained within single-quotation marks. This is necessary
because the table columns are defined to contain character strings. Numeric data does not require the quotation marks.
Updating data in a database
Use the UPDATE statement in SQL to update the values of a table row. Update lets you update the fields of a specific
row or all rows in the table. The UPDATE statement has the following syntax:
UPDATE table_name
SET column_name1=value1, ... , column_nameN=valueN
[ WHERE search_condition ]
Note: There are additional options to UPDATE depending on your database. For a complete syntax description for
UPDATE, see the product documentation.
Do not attempt to update a records primary key field. Your database typically enforces this restriction.
The UPDATE statement uses the optional WHERE clause, much like the SELECT statement, to determine which table
rows to modify. The following UPDATE statement updates the e-mail address of John Smith:
UPDATE employees SET Email='[email protected]' WHERE EmpID = 51
Be careful using UPDATE. If you omit the WHERE clause to execute the following statement:
UPDATE employees SET Email = '[email protected]'
you update the Email field for all rows in the table.
Deleting data from a database
The DELETE statement removes rows from a table. The DELETE statement has the following syntax:
DELETE FROM table_name
[ WHERE search_condition ]
Note: There are additional options to DELETE depending on your database. For a complete syntax description for
DELETE, see the product documentation.
You can remove all rows from a table using a statement in the form:
DELETE FROM employees
Typically, you specify a WHERE clause to the DELETE statement to delete specific rows of the table. For example, the
following statement deletes John Smith from the table:
DELETE FROM employees WHERE EmpID=51
410
<cftransaction>
<cfquery name="qInsEmp" datasource="cfdocexamples">
INSERT INTO Employees (FirstName,LastName,EMail,Phone,Department)
VALUES ('Simon', 'Horwith', 'SHORWITH','(202)-797-6570','Research and Development')
</cfquery>
<cfquery name="qGetID" datasource="cfdocexamples">
SELECT MAX(Emp_ID) AS New_Employee
FROM Employees
</cfquery>
</cftransaction>
Retrieving data
You can query databases to retrieve data at run time. The retrieved data, called the recordset, is stored on that page as
a query object. A query object is a special entity that contains the recordset values, plus RecordCount, CurrentRow,
ColumnList, SQL, Cached, and SQLParameter query variables. You specify the name of the query object in the name
attribute of the cfquery tag. The query object is often called simply the query.
The following is a simple cfquery tag:
<cfquery name = "GetSals" datasource = "cfdocexamples">
SELECT * FROM Employee
ORDER BY LastName
</cfquery>
411
Note: The terms recordset and query object are often used synonymously when discussing recordsets for queries. For
more information, see Using Query of Queries on page 428.
When retrieving data from a database, perform the following tasks:
To tell ColdFusion how to connect to a database, use the cfquery tag on a page.
To specify the data that you want to retrieve from the database, write SQL commands inside the cfquery block.
Reference the query object and use its data values in any tag that presents data, such as cfoutput, cfgrid, cftable,
cfgraph, or cftree.
Use opening <cfquery> and ending </cfquery> tags, because the cfquery tag is a block tag.
Enter the query name and datasource attributes within the opening cfquery tag.
To tell the database what to process during the query, place SQL statements inside the cfquery block.
When referencing text literals in SQL, use single-quotation marks ('). For example, SELECT
* FROM mytable
WHERE FirstName='Jacob' selects every record from mytable in which the first name is Jacob.
When ColdFusion returns database columns, it removes table and owner prefixes. For example, if you query
Employee.Emp_ID in the query, the Employee, is removed and returns as Emp_ID. You can use an alias to handle
duplicate column names; for more information, see Using Query of Queries on page 428.
You cannot use SQL reserved words, such as MIN, MAX, COUNT, in a SQL statement. Because reserved words are
database-dependent, see the documentation of your database for a list of reserved words.
412
If you use COMPUTE AVG() in your SQL, ColdFusion 9 returns avg() as the column name. (Previous versions
(ColdFusion 5 and ColdFusion MX 7) returned ave() as the column name.)
To retrieve results returned by database triggers, add the following connection parameter in the connection string:
AlwaysReportTriggerResults=true
This parameter determines how the driver reports results generated by database triggers (procedures that are stored
in the database and executed, or fired, when a table is modified). For Microsoft SQL Server 2005, this includes
triggers fired by Data Definition Language (DDL) events. If set to true, the driver returns all results, including
results generated by triggers. Multiple trigger results are returned one at a time. Use the method
Statement.getMoreResults to retrieve individual trigger results. Warnings and errors are reported in the results as
they are encountered.
Building queries
As discussed earlier, you build queries by using the cfquery tag and SQL.
Note: This procedure and many subsequent procedures use the cfdocexamples data source that connects to the
cfdocexamples.mdb database. This data source is installed by default. For information on adding or configuring a data
source, see Configuring and Administering ColdFusion.
Query the table
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>Employee List</title>
</head>
<body>
<h1>Employee List</h1>
<cfquery name="EmpList" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary, Contract
FROM Employee
</cfquery>
</body>
</html>
Note: Adobe recommends that you create structured, reusable code by placing queries in ColdFusion components;
however, for simplicity, the examples here include the query in the body of the ColdFusion page. For more information
about using ColdFusion components, see Building and Using ColdFusion Components on page 177.
2 Save the page as emplist.cfm in the myapps directory under your web_root directory. For example, the default path
http://localhost/myapps/emplist.cfm
Only the header appears.
4 View the source in the browser.
ColdFusion creates the EmpList data set, but only HTML and text return to the browser. When you view the pages
source, you see only HTML tags and the heading Employee List. To display the data set on the page, use code tags
and variables to output the data.
413
Description
FROM Employee
</cfquery>
ColdFusion loops through all the code contained within the cfoutput block, once for each row in the recordset
returned from the database.
Reference specific column names within the cfoutput block to output the data to the page.
You can place text, CFML tags, and HTML tags inside or surrounding the cfoutput block to format the data on
the page.
Although you do not have to specify the query name when you refer to a query column, use the query name as a
prefix for best practices reasons. For example, if you specify the Emplist query in your cfoutput tag, you can refer
to the Firstname column in the Emplist query as Firstname. However, using the query name as a prefix,
Emplist.Firstname, is preferred, and is in the following procedure.
The cfoutput tag accepts a variety of optional attributes but, ordinarily, you use the query attribute to define the
name of an existing query.
1 Edit emplist.cfm so that it appears as follows:
<html>
<head>
<title>Employee List</title>
</head>
<body>
<h1>Employee List</h1>
<cfquery name="EmpList" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary, Contract
FROM Employee
</cfquery>
<cfoutput query="EmpList">
#EmpList.FirstName#, #EmpList.LastName#, #EmpList.Salary#, #EmpList.Contract#<br>
</cfoutput>
</body>
</html>
A list of employees appears in the browser, with each line displaying one row of data.
Note: If necessary, refresh your browser to see your changes.
414
You created a ColdFusion application page that retrieves and displays data from a database. At present, the output is
raw and needs formatting. For more information, see Introduction to Retrieving and Formatting Data on page 703.
Reviewing the code
The results of the query appear on the page. The following table describes the highlighted code and its function:
Code
Description
<cfoutput query="EmpList">
#EmpList.FirstName#, #EmpList.LastName#,
#EmpList.Salary#, #EmpList.Contract#
<br>
Inserts a line break (go to the next line) after each record.
</cfoutput>
A cfquery must retrieve data before the cfoutput tag can display its results. Although you can include both on
the same page, Adobe recommends that you place queries in ColdFusion components and output the results on a
separate page. For more information, see Building and Using ColdFusion Components on page 177.
To output data from all the records of a query, specify the query name by using the query attribute in the cfoutput tag.
Columns must exist and be retrieved to the application to output their values.
Inside a cfoutput block that uses a cfquery attribute, you can prefix the query variables with the name of the
query; for example, Emplist.FirstName.
As with other attributes, surround the query attribute value with double-quotation marks (").
As with any variables that you reference for output, surround column names with number signs (#) to tell
ColdFusion to output the current values of the column.
Add a <br> tag to the end of the variable references so that ColdFusion starts a new line for each row that the query
returns.
Description
RecordCount
ColumnList
SQL
Cached
SQLParameters
ExecutionTime
415
In your CFML code, use these variables as if they are columns in a database table. Use the result attribute to specify
the name of the structure that ColdFusion populates with these variables. You then use that structure name to refer to
the query variables as the following example shows:
The number of employees now appears below the list of employees. If necessary, refresh your browser and scroll to
see the RecordCount output.
Reviewing the code
You now display the number of records retrieved in the query. The following table describes the code and its function:
Code
Description
<cfoutput>
#EmpList.RecordCount#
records.
</cfoutput>
Reference the query variable within a cfoutput block so that ColdFusion outputs the query variable value to the page.
Surround the query variable reference with number signs (#) so that ColdFusion knows to replace the variable
name with its current value.
Do not use the cfoutput tag query attribute when you output the RecordCount or ColumnList property. If you
do, you get one copy of the output for each row. Instead, prefix the variable with the name of the query.
416
Someone could call this page with the following malicious URL:
http://myserver/page.cfm?Emp_ID=7%20DELETE%20FROM%20Employee
The result is that ColdFusion tries to execute the following query:
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT * FROM Employee
WHERE Emp_ID = 7 DELETE FROM Employee
</cfquery>
In addition to an expected integer for the Emp_ID column, this query also passes malicious string code in the form of
a SQL statement. If this query successfully executes, it deletes all rows from the Employee tablesomething you
definitely do not want to enable by this method. To prevent such actions, evaluate the contents of query string
parameters.
Using cfqueryparam
You can use the cfqueryparam tag to evaluate query string parameters and pass a ColdFusion variable within a SQL
statement. This tag evaluates variable values before they reach the database. You specify the data type of the
corresponding database column in the cfsqltype attribute of the cfqueryparam tag. In the following example,
because the Emp_ID column in the cfdocexamples data source is an integer, you specify a cfsqltype of
cf_sql_integer:
<cfquery name="EmpList" datasource="cfdocexamples">
SELECT * FROM Employee
WHERE Emp_ID = <cfqueryparam value = "#Emp_ID#"
cfsqltype = "cf_sql_integer">
</cfquery>
The cfqueryparam tag checks that the value of Emp_ID is an integer data type. If anything else in the query string is
not an integer, such as a SQL statement to delete a table, the cfquery tag does not execute. Instead, the cfqueryparam
tag returns the following error message:
Invalid data '7 DELETE FROM Employee' for CFSQLTYPE 'CF_SQL_INTEGER'.
Using cfqueryparam with strings
When passing a variable that contains a string to a query, specify a cfsqltype value of cf_sql_char, and specify the
maxLength attribute, as in the following example:
417
BIT
CHAR
DATE
DECIMAL
DOUBLE
FLOAT
IDSTAMP
INTEGER
LONGVARCHAR
MONEY
MONEY4
NUMERIC
REAL
REFCURSOR
SMALLINT
TIME
TIMESTAMP
TINYINT
VARCHAR
Note: Specifying the cfsqltype attribute causes the DBMS to use bind variables, which can greatly enhance
performance.
Inserting data
You usually use two application pages to insert data into a database:
An insert form
An insert action page
418
You can create an insert form with standard HTML form tags or with cfform tags (see Creating custom forms with
the cfform tag on page 723). When the user submits the form, form variables are passed to a ColdFusion action page
that performs an insert operation (and whatever else is called for) on the specified data source. The insert action page
can contain either a cfinsert tag or a cfquery tag with a SQL INSERT statement. The insert action page should also
contain a confirmation message for the end user.
419
</tr>
<tr>
<td>Salary:</td>
<td><input type="Text" name="Salary" size="10" maxlength="10"></td>
</tr>
<tr>
<td>Contractor:</td>
<td><input type="checkbox" name="Contract" value="Yes" checked>Yes</td>
</tr>
<tr>
<td> </td>
<td><input type="Submit" value="Submit"> <input type="Reset"
value="Clear Form"></td>
</tr>
</form>
<!--- end html form --->
</table>
</body>
</html>
2 Save the file as insert_form.cfm in the myapps directory under your web_root and view it in your web browser.
Note: The form does not work until you write an action page for it. For more information, see Creating an action page
to insert data on page 419.
Create HTML form fields for only the database columns into which you insert data.
By default, cfinsert inserts all of the forms fields into the database columns with the same names. For example,
it places the Form.Emp_ID value in the database Emp_ID column. The tag ignores form fields that lack
corresponding database column names.
Note: You can also use the formfields attribute of the cfinsert tag to specify which fields to insert; for example,
formfields="prod_ID,Emp_ID,status".
420
<html>
<head> <title>Input form</title> </head>
<body>
<!--- If the Contractor check box is clear,
set the value of the Form.Contract to "No" --->
<cfif not isdefined("Form.Contract")>
<cfset Form.Contract = "N">
</cfif>
<!--- Insert the new record --->
<cfinsert datasource="cfdocexamples" tablename="EMPLOYEE">
<h1>Employee Added</h1>
<cfoutput> You have added #Form.FirstName# #Form.Lastname# to the employee database.
</cfoutput>
</body>
</html>
Note: You might want to compare views of the Employee table in the cfdocexamples data source before and after
inserting values in the form.
4 Click Submit.
ColdFusion inserts your values into the Employee table and displays a confirmation message.
Reviewing the code
The following table describes the code and its function:
Code
Description
<cfinsert datasource="cfdocexamples"
tablename="EMPLOYEE">
Creates a row in the Employee table of the cfdocexamples database. Inserts data
from the form into the database fields with the same names as the form fields.
Informs the user that values were inserted into the database.
Note: If you use form variables in cfinsert or cfupdate tags, ColdFusion automatically validates any form data it
sends to numeric, date, or time database columns. You can use the hidden field validation functions for these fields to
display a custom error message. For more information, see Introduction to Retrieving and Formatting Data on
page 703.
Creating an insert action page with cfquery
For more complex inserts from a form submittal, you can use a SQL INSERT statement in a cfquery tag instead of
using a cfinsert tag. The SQL INSERT statement is more flexible because you can insert information selectively or
use functions within the statement.
421
The following procedure assumes that you have created the insert_action.cfm page, as described in Creating an insert
action page with cfinsert on page 419.
1 In insert_action.cfm, replace the cfinsert tag with the following highlighted cfquery code:
<html>
<head>
<title>Input form</title>
</head>
<body>
<!--- If the Contractor check box is clear), set the value of the Form.Contract
to "No" --->
<cfif not isdefined("Form.Contract")>
<cfset Form.Contract = "No">
</cfif>
<!--- Insert the new record --->
<cfquery name="AddEmployee" datasource="cfdocexamples">
INSERT INTO Employee
VALUES (#Form.Emp_ID#, '#Form.FirstName#',
'#Form.LastName#', #Form.Dept_ID#,
'#Form.StartDate#', #Form.Salary#, '#Form.Contract#')
</cfquery>
<h1>Employee Added</h1>
<cfoutput>You have added #Form.FirstName# #Form.Lastname# to the employee database.
</cfoutput>
</body>
</html>
ColdFusion inserts your values into the Employee table and displays a confirmation message.
Reviewing the code
The following table describes the highlighted code and its function:
Code
Description
<cfquery name="AddEmployee"
datasource="cfdocexamples">
INSERT INTO Employee VALUES
(#Form.Emp_ID#,
'#Form.FirstName#',
'#Form.LastName#',
#Form.Dept_ID#,
'#Form.StartDate#',
#Form.Salary#, '#Form.Contract#')
</cfquery>
Inserts a new row into the Employee table of the cfdocexamples database. Specifies each form
field to be added.
Because you are inserting data into all database fields in the same left-to-right order as in the
database, you do not have to specify the database field names in the query.
Because #From.Emp_ID#, #Form.Dept_ID#, and #Form.Salary# are numeric, they do
not need to be enclosed in quotation marks.
422
Updating data
You usually use the following two application pages to update data in a database:
An update form
An update action page
You can create an update form with cfform tags or HTML form tags. The update form calls an update action page,
which can contain either a cfupdate tag or a cfquery tag with a SQL UPDATE statement. The update action page
should also contain a confirmation message for the end user.
An update form contains a reference to the primary key of the record that is being updated.
A primary key is a fields in a database table that uniquely identifies each record. For example, in a table of employee
names and addresses, only the Emp_ID is unique to each record.
423
<html>
<head>
<title>Update Form</title>
</head>
<body>
<cfquery name="GetRecordtoUpdate" datasource="cfdocexamples">
SELECT * FROM Employee
WHERE Emp_ID = #URL.Emp_ID#
</cfquery>
<cfoutput query="GetRecordtoUpdate">
<table>
<form action="update_action.cfm" method="Post">
<input type="Hidden" name="Emp_ID" value="#Emp_ID#"><br>
<tr>
<td>First Name:</td>
<td><input type="text" name="FirstName" value="#FirstName#"></td>
</tr>
<tr>
<td>Last Name:</td>
<td><input type="text" name="LastName" value="#LastName#"></td>
</tr>
<tr>
<td>Department Number:</td>
<td><input type="text" name="Dept_ID" value="#Dept_ID#"></td>
</tr>
<tr>
<td>Start Date:</td>
<td><input type="text" name="StartDate" value="#StartDate#"></td>
</tr>
<tr>
<td>Salary:</td>
<td><input type="text" name="Salary" value="#Salary#"></td>
</tr>
<tr>
<td>Contractor:</td>
<td><cfif #Contract# IS "Yes">
<input type="checkbox" name="Contract" checked>Yes
<cfelse>
<input type="checkbox" name="Contract">Yes
</cfif></td>
</tr>
<tr>
<td> </td>
<td><input type="Submit" value="Update Information"></td>
</tr>
</form>
</table>
</cfoutput>
</body>
</html>
424
3 View update_form.cfm in your web browser by specifying the page URL and an Employee ID; for example, enter
Description
<cfquery name="GetRecordtoUpdate"
datasource="cfdocexamples">
SELECT * FROM Employee
WHERE Emp_ID = #URL.Emp_ID#
</cfquery>
<cfoutput query="GetRecordtoUpdate">
...
</cfoutput>
Uses a hidden input field to pass the Emp_ID (primary key) value to
the action page.
First Name:
<input type="text" name="FirstName"
value="#FirstName#"><br>
Last Name:
<input type="text" name="LastName"
value="#LastName#"><br>
Department Number:
<input type="text" name="Dept_ID"
value="#Dept_ID#"><br>
Start Date:
<input type="text" name="StartDate"
value="#StartDate#"><br>
Salary:
<input type="text" name="Salary"
value="#Salary#"><br>
Populates the fields of the update form. This example does not use
ColdFusion formatting functions. As a result, start dates look like
1985-03-12 00:00:00 and salaries do not have dollar signs or commas.
The user can replace the information in any field using any valid input
format for the data.
Contracto r:
< cfif #Contract# IS "Yes">
<input type="checkbox" name="C ontract"
checked>Yes<br>
<cfelse>
<input type="checkbox" name="Contract"> Yes <br>
</cfif>
<br>
<input type="Submit" value="Update Information">
</form>
</cfoutput>
425
To use the cfupdate tag, include the primary key fields in your form submittal. The cfupdate tag automatically
detects the primary key fields in the table that you are updating and looks for them in the submitted form fields.
ColdFusion uses the primary key fields to select the record to update (therefore, you cannot update the primary key
value itself). It then uses the remaining form fields that you submit to update the corresponding fields in the record.
Your form only needs to have fields for the database fields that you want to change.
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>Update Employee</title>
</head>
<body>
<cfif not isdefined("Form.Contract")>
<cfset form.contract = "N">
<cfelse>
<cfset form.contract = "Y">
</cfif>
<cfupdate datasource="cfdocexamples" tablename="EMPLOYEE">
<h1>Employee Updated</h1>
<cfoutput>
You have updated the information for #Form.FirstName# #Form.LastName# in the employee
database.
</cfoutput>
</body>
</html>
ColdFusion updates the record in the Employee table with your new values and displays a confirmation message.
Reviewing the code
The following table describes the code and its function:
Code
Description
<cfupdate datasource="cfdocexamples"
tablename="EMPLOYEE">
Updates the record in the database that matches the primary key on the
form (Emp_ID). Updates all fields in the record with names that match the
names of form controls.
<cfoutput>
You have updated the information for
#Form.FirstName# #Form.LastName# in the employee
database.
</cfoutput>
426
ColdFusion updates the record in the Employee table with your new values and displays a confirmation message.
When the cfquery tag retrieves date information from a Microsoft Access database, it displays the date and time with
tenths of seconds, as follows:
Deleting data
You use a cfquery tag with a SQL DELETE statement to delete data from a database. ColdFusion has no cfdelete tag.
427
You often want to see the data before you delete it. The following procedure displays the data to be deleted by reusing
the form page used to insert and update data. Any data that you enter in the form before submitting it is not used, so
you can use a table to display the record to be deleted instead.
1 In update_form.cfm, change the title to Delete Form and the text on the submit button to Delete Record.
2 Change the form tag so that it appears as follows:
<form action="delete_action.cfm" method="Post">
Description
<cfquery name="DeleteEmployee"
datasource="cfdocexamples">
DELETE FROM Employee WHERE Emp_ID = #Form.Emp_ID#
</cfquery>
Deletes the record in the database whose Emp_ID column matches the
Emp_ID (hidden) field on the form. Since the Emp_ID is the tables primary
key, only one record is deleted.
<cfoutput>
You have deleted #Form.FirstName#
#Form.LastName# from the employee database.
</cfoutput>
428
To delete all the records from the Employee table, use the following code:
DELETE FROM Employee
Important: Deleting records from a database is not reversible. Use DELETE statements carefully.
About recordsets
Query of Queries is based on manipulating the recordset, which you can create using the cfquery tag and other ways.
When you execute a database query, Adobe ColdFusion retrieves the data in a recordset. In addition to presenting
recordset data to the user, you can manipulate this recordset to improve the performance of your application.
Because a recordset contains rows (records) and columns (fields), you can think of it as a virtual database table, or as
a spreadsheet. For example, the cfpop tag retrieves a recordset in which each row is a message and each column is a
message component, such as To, From, and Subject.
Creating a recordset
You can perform a Query of Queries on any ColdFusion tag or function that generates a recordset, including the
following:
cfcollection
cfdirectory
cfftp
cfhttp
cfindex
cfldap
cfmail
cfpop
cfprocresult
cfsearch
cfstoredproc
cfwddx
429
2 Save the page as queryNew.cfm in the myapps directory under the web_root directory.
3 Display queryNew.cfm in your browser
430
Note: Because you can generate a recordset in ways other than using the cfquery tag, the term In Memory Query is
sometimes used instead of Query of Queries.
For example, you can perform a union operation on queries from different databases to eliminate duplicates for a
mailing list.
3 You can efficiently manipulate cached query results in different ways. You can query a database once, and then use
For example, you can select information about departments and employees in a query, and cache the results. You
can then display the names of the employees. When users select an employee, the application displays the details of
the employees by selecting information from the cached query, without accessing the database.
5 You can use a Query of Queries in report definitions to generate subreport data. For more information, see Using
You can write a master query using a tag or function that creates a recordset. For more information, see Creating
a recordset on page 428.
2 Write a detail querya cfquery tag that specifies dbtype="query".
3 In the detail query, write a SQL statement that retrieves the relevant records. Specify the names of one or more
existing queries as the table names in your SQL code. Do not specify a datasource attribute.
4 If the database content does not change rapidly, use the cachedwithin attribute of the master query to cache the
query results between page requests. This way, ColdFusion accesses the database on the first page request, and does
not query the database again until the specified time expires. Use the CreateTimeSpan function to specify the
cachedwithin attribute value (in days, hours, minutes, seconds format).
The detail query generates a new query result set, identified by the value of the name attribute of the detail query. The
following example illustrates the use of a master query and a single detail query that extracts information from the
master.
Use the results of a query in a query
1 Create a ColdFusion page with the following content:
431
<h1>Employee List</h1>
<!--- LastNameSearch (normally generated interactively) --->
<cfset LastNameSearch="Doe">
<!--- Master Query --->
<cfquery datasource="cfdocexamples" name="master"
cachedwithin=#CreateTimeSpan(0,1,0,0)#>
SELECT * from Employee
</cfquery>
<!--- Detail Query (dbtype=query, no data source) --->
<cfquery dbtype="query" name="detail">
SELECT Emp_ID, FirstName, LastName
FROM master
WHERE LastName=<cfqueryparam value="#LastNameSearch#"
cfsqltype="cf_sql_char" maxLength="20"></cfquery>
<!--- output the detail query results --->
<p>Output using a query of query:</p>
<cfoutput query=detail>
#Emp_ID#: #FirstName# #LastName#<br>
</cfoutput>
<p>Columns in the master query:</p>
<cfoutput>
#master.columnlist#<br>
</cfoutput>
<p>Columns in the detail query:</p>
<cfoutput>
#detail.columnlist#<br>
</cfoutput>
2 Save the page as query_of_query.cfm in the myapps directory under the web_root.
3 Display query_of_query.cfm in your browser
Description
cfset LastNameSearch="Doe"
Sets the last name to use in the detail query. In a complete application,
this information comes from user interaction.
Queries the cfdocexamples data source and selects all data in the
Employees table. Caches the query data between requests to this page,
and does not query the database if the cached data is less than an hour
old.
Uses the master query as the source of the data in a new query, named
detail. This new query selects only entries that match the last name
specified by the LastNameSearch variable. The query also selects only
three columns of data: employee ID, first name, and last name. The query
uses the cfqueryparam tag to prevent passing erroneous or harmful code.
432
Code
Description
<cfoutput query=detail>
#Emp_ID#: #FirstName# #LastName# <br>
</cfoutput>
Uses the detail query to display the list of employee IDs, first names, and
last names.
<cfoutput>
#master.columnlist#<br>
</cfoutput>
<cfoutput>
#detail.columnlist#<br>
</cfoutput>
433
2 Save the page as qoq_next_row.cfm in the myapps directory under the web_root.
3 Display qoq_next_row.cfm in your browser.
For more information on the cfdump tag, see the CFML Reference.
434
2 Save the page as qoq_verity.cfm in the myapps directory under the web_root.
3 Display qoq_verity.cfm in your browser
The next example shows how a Query of Queries combines recordsets from a cfdirectory tag, which is limited to
retrieval of one file type per use.
435
<html>
<head>
<title>Images Folder</title>
</head>
<body>
<h2>Image Retrieval with QoQ</h2>
<!--- Set the images directory. --->
<cfset dir = ("C:\pix\")>
<!--- Retrieve all GIFs. --->
<cfdirectory name="GetGIF"
action="list"
directory="#dir#"
filter="*.gif">
<!--- Retrieve all JPGs --->
<cfdirectory name="GetJPG"
action="list"
directory="#dir#"
filter="*.jpg">
<!--- Join the queries with a UNION in a QoQ (cfdirectory
automatically returns the directory name as "Name"). --->
<cfquery dbtype="query" name="GetBoth">
SELECT * FROM GetGIF
UNION
SELECT * FROM GetJPG
ORDER BY Name
</cfquery>
<!--- Display output in a linked, ordered list. --->
<cfoutput>
<p>The <strong>#dir#</strong> directory contains #GetBoth.RecordCount#
images:<br>
<ol>
<cfloop query="GetBoth">
<li><a href="../images/#Name#">#GetBoth.Name#</a><br>
</cfloop>
</ol>
</cfoutput>
</body>
</html>
2 Save the page as qoq_cfdirectory.cfm in the myapps directory under the web_root.
3 Display qoq_cfdirectory.cfm in your browser.
436
Example
If a structure named A contains a field named B, which contains a table named Products, you can refer to the table with
dot notation, as follows:
SELECT tape_ID, length
FROM A.B.Products;
Using joins
A join operation uses a single SELECT statement to return a result set from multiple, related tables, typically those
tables with a primary key - foreign key relationship. The two SQL clauses that perform joins are:
Using unions
The UNION operator lets you combine the results of two or more SELECT expressions into a single recordset. The
original tables must have the same number of columns, and corresponding columns must be UNION-compatible data
types. Columns are UNION-compatible data types if they meet one of the following conditions:
Example
This example uses the following tables:
Table1
Type(int)
Name(varchar)
Tennis
Baseball
Football
Table2
ID(int)
Sport(varchar)
Football
Volleyball
PingPong
437
Name(varchar)
Tennis
Baseball
Football
Volleyball
PingPong
438
/* First statement. */
SELECT * FROM TableA
UNION ALL
(SELECT * FROM TableB
UNION
SELECT * FROM TableC
)
/* Second statement. */
(SELECT * FROM TableA
UNION ALL
SELECT * FROM TableB
)
UNION
SELECT * FROM TableC
In the first statement, there are no duplicates in the union between TableB and TableC. Then, in the union between
that set and TableA, the ALL keyword includes the duplicates. In the second statement, duplicates are included in the
union between TableA and TableB but are eliminated in the subsequent union with TableC. The ALL keyword has no
effect on the final result of this expression.
Using other keywords with UNION
When you perform a UNION, the individual SELECT statements cannot have their own ORDER BY or COMPUTE
clauses. You can only have one ORDER BY or COMPUTE clause after the last SELECT statement; this clause is applied
to the final, combined result set. You can only specify GROUP BY and HAVING expressions in the individual SELECT
statements.
Example
SELECT _isValid FROM Chemicals
WHERE _isValid IS true;
Null conditional
This conditional tests whether an expression is null.
Syntax
null_cond ::= expression IS [NOT] NULL
Example
SELECT bloodVal FROM Standards
WHERE bloodVal IS NOT null;
439
Comparison conditional
This conditional lets you compare an expression against another expression of the same data type (Numeric, String,
Date, or Boolean). You can use it to selectively retrieve only the relevant rows of a recordset.
Syntax
comparison_cond ::= expression [> | >= | <> | != | < | <=] expression
Example
The following example uses a comparison conditional to retrieve only those dogs whose IQ is at least 150:
SELECT dog_name, dog_IQ
FROM Dogs
WHERE dog_IQ >= 150;
BETWEEN conditional
This conditional lets you compare an expression against another expression. You can use it to selectively retrieve only
the relevant rows of a recordset. Like the comparison conditional, the BETWEEN conditional also compares; however,
the BETWEEN conditional compares against a range of values. Therefore, its syntax requires two values, which are
inclusive, a minimum and a maximum. Separate these values with the AND keyword.
Syntax
between_cond ::= expression [NOT] BETWEEN expression AND expression
Example
The following example uses a BETWEEN conditional to retrieve only those dogs whose IQ is between 150 and 165,
inclusive:
SELECT dog_name, dog_IQ
FROM Dogs
WHERE dog_IQ BETWEEN 150 AND 165;
IN conditional
This conditional lets you specify a comma-delimited list of conditions to match. It is similar in function to the OR
conditional. In addition to being more legible when working with long lists, the IN conditional can contain another
SELECT statement.
Syntax
in_cond ::= expression [NOT] IN (expression_list)
Example
The following example uses the IN conditional to retrieve only those dogs who were born at either Kens Kennels or
Barbs Breeders:
SELECT dog_name, dog_IQ, Kennel_ID
FROM Dogs
WHERE kennel_ID IN ('Kens','Barbs');
LIKE conditional
This conditional lets you perform wildcard searches, in which you compare your data to search patterns. This strategy
differs from other conditionals, such as BETWEEN or IN, because the LIKE conditional compares your data to a value
that is partially unknown.
440
Syntax
like_cond ::= left_string_exp [NOT] LIKE right_string_exp [ESCAPE escape_char]
The left_string_exp can be either a constant string, or a column reference to a string column. The right_string_exp can
be either a column reference to a string column, or a search pattern. A search pattern is a search condition that consists
of literal text and at least one wildcard character. A wildcard character is a special character that represents an unknown
part of a search pattern, and is interpreted as follows:
The following examples are select statements that use bracketed ranges:
SELECT
SELECT
SELECT
SELECT
SELECT
lname
lname
lname
lname
lname
FROM
FROM
FROM
FROM
FROM
Suspects
Suspects
Suspects
Suspects
Suspects
WHERE
WHERE
WHERE
WHERE
WHERE
lname
lname
lname
lname
lname
LIKE
LIKE
LIKE
LIKE
LIKE
'A[^c]%';
'[a-m]%';
'%[]';
'A[%]%';
'A[^c-f]%';
Case sensitivity
Unlike the rest of ColdFusion, Query of Queries is case-sensitive. However, Query of Queries supports two string
functions, UPPER() and LOWER(), which you can use to achieve case-insensitive matching.
Examples
The following example matches only 'Sylvester':
SELECT dog_name
FROM Dogs
WHERE dog_name LIKE 'Sylvester';
The following example is not case sensitive; it uses the LOWER() function to treat 'Sylvester', 'sylvester', 'SYLVESTER',
and so on, as all lowercase, and matches them with the all lowercase string, sylvester:
SELECT dog_name
FROM Dogs
WHERE LOWER(dog_name) LIKE 'sylvester';
If you use a variable on the right side of the LIKE conditional and want to ensure that the comparison is not casesensitive, use the LCase or UCase function to force the variable text to be all of one case, as in the following example:
WHERE LOWER(dog_name) LIKE '#LCase(FORM.SearchString)#';
441
Escaping wildcards
You can specify your own escape character by using the conditional ESCAPE clause.
Example
The following example uses the ESCAPE clause to enable a search for a literal percent sign (%), which ColdFusion
normally interprets as a wildcard character:
SELECT emp_discount
FROM Benefits
WHERE emp_discount LIKE '10\%'
ESCAPE '\';
Note: To see the metadata for a Query of Queries, use the GetMetaData function.
Specify the column data types in the QueryAddColumn function
1 Create a query by specifying the QueryNew function with no parameters.
<!--- Make a query. --->
<cfset myQuery = QueryNew("")>
2 Add and populate a column with the QueryAddColumn function, specifying the data type in the third parameter:
<!--- Create an array. --->
<cfset FastFoodArray = ArrayNew(1)>
<cfset FastFoodArray[1] = "French Fries">
<cfset FastFoodArray[2] = "Hot Dogs">
<cfset FastFoodArray[3] = "Fried Clams">
<cfset FastFoodArray[4] = "Thick Shakes">
<!--- Use the array to add a column to the query. --->
<cfset nColumnNumber = QueryAddColumn(myQuery, "FastFood", "CF_SQL_VARCHAR",
FastFoodArray)>
If you do not specify the data type, ColdFusion examines the first 50 rows of each column to determine the data type
when performing conditional expressions.
In some cases, ColdFusion can guess a data type that is inappropriate for your application. In particular, if you use
columns in a WHERE clause or other conditional expression, the data types must be compatible. If they are not
compatible, use the CAST function to recast one of the columns to a compatible data type. For more information on
casting, see Using the CAST function on page 442. For more information on data type compatibility, see
Understanding Query of Queries processing on page 448.
Note: Specifying the data type in the QueryNew function helps you avoid compatibility issues.
442
BINARY
BIGINIT
BIT
DATE
DECIMAL
DOUBLE
INTEGER
TIME
TIMESTAMP
VARCHAR
For example:
<cfhttp
url="http://quote.yahoo.com/download/quotes.csv?Symbols=csco,jnpr&format=sc1l1&ext=.csv"
method="GET"
name="qStockItems"
columns="Symbol,Change,LastTradedPrice"
textqualifier=""""
delimiter=","
firstrowasheaders="no">
<cfoutput>
<cfdump var="#qStockItems#">
<cfdump var="#qStockItems.getColumnNames()#">
</cfoutput>
<cfoutput>
<cfloop index="i" from="1" to="#arrayLen(qStockItems.getColumnNames())#">
#qStockItems.getMetaData().getColumnTypeName(javaCast("int",i))#<br/>
</cfloop>
</cfoutput>
<cftry>
<cfquery name="hello" dbtype="query">
SELECT SUM(CAST(qStockItems.LastTradedPrice as INTEGER))
AS SUMNOW from qStockItems
</cfquery>
<cfcatch>Error in Query of Queries</cfcatch>
</cftry>
<cfoutput>
<cfdump var="#hello#">
</cfoutput>
443
Description
AVG()
COUNT()
MAX()
MIN()
SUM()
Syntax
aggregate_func ::= <COUNT>(* | column_name) | AVG | SUM | MIN | MAX)
([ALL | DISTINCT] numeric_exp)
Example
The following example uses the AVG() function to retrieve the average IQ of all terriers:
SELECT dog_name, AVG(dog_IQ) AS avg_IQ
FROM Dogs
WHERE breed LIKE '%Terrier';
444
Examples
The following code is correct:
SELECT (lorange + hirange)/2 AS midrange,
COUNT(*)
FROM roysched
GROUP BY midrange;
Example
The following example shows a simple sort using an ORDER BY clause:
SELECT acetylcholine_levels, dopamine_levels
FROM results
ORDER BY dopamine_levels
The following example shows a more complex sort; results are first sorted by ascending levels of dopamine, then by
descending levels of acetylcholine. The ASC keyword is unnecessary, and is used only for legibility.
SELECT acetylcholine_levels, dopamine_levels
FROM results
ORDER BY 2 ASC, 1 DESC
Using aliases
Query of Queries supports the use of database column aliases. An alias is an alternate name for a database field or
value. Query of Queries lets you reuse an alias in the same SQL statement.
One way to create an alias is to concatenate (append) two or more columns to generate a value. For example, you can
concatenate a first name and a last name to create the value fullname. Because the new value does not exist in a
database, you refer to it by its alias. The AS keyword assigns the alias in the SELECT statement.
Examples
Query of Queries supports alias substitutions in the ORDER BY, GROUP BY, and HAVING clauses.
445
Note: Query of Queries does not support aliases for table names.
SELECT FirstName + ' ' + LastName AS fullname
from Employee;
ORDER BY example
<cfquery name="order_by" dbtype="query">
SELECT (job_id || job_lvl)/2 AS job_value
FROM employee
ORDER BY job_value
</cfquery>
GROUP BY example
<cfquery name="group_by" dbtype="query">
SELECT lorange || hirange AS x, count(hirange)
FROM roysched
GROUP BY x
</cfquery>
HAVING example
<cfquery name="having" dbtype="query">
SELECT (lorange || hirange)/2 AS x,
COUNT(*)
FROM roysched GROUP BY x
HAVING x > 10000
</cfquery>
The correct behavior should not include NULL breed columns in the result set of either expression. To avoid this
limitation, add an explicit rule to the conditionals and rewrite them in the following forms:
WHERE breed IS NOT NULL AND (breed > 'A')
WHERE breed IS NOT NULL AND not (breed > 'A')
Concatenating strings
Query of Queries support two string concatenation operators: + and ||, as the following examples show:
LASTNAME + ', ' + FIRSTNAME
LASTNAME || ', ' || FIRSTNAME
446
Query of Queries does not support nested escapes, such as in the following example:
SELECT [[from]] FROM T;
ACTION
ADD
ALL
ALLOCATE
ALTER
AND
ANY
ARE
AS
ASC
ASSERTION
AT
AUTHORIZATION
AVG
BEGIN
BETWEEN
BIT
BIT_LENGTH
BOTH
BY
CASCADE
CASCADED
CASE
CAST
CATALOG
CHAR
CHARACTER
CHARACTER_LENGTH
CHAR_LENGTH
CHECK
CLOSE
COALESCE
COLLATE
COLLATION
COLUMN
COMMIT
CONNECT
CONNECTION
CONSTRAINT
CONSTRAINTS
CONTINUE
CONVERT
CORRESPONDING
COUNT
CREATE
CROSS
CURRENT
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_USER
CURSOR
DATE
DAY
DEALLOCATE
DEC
DECIMAL
DECLARE
DEFAULT
DEFERRABLE
DEFERRED
DELETE
DESC
DESCRIBE
DESCRIPTOR
DIAGNOSTICS
DISCONNECT
DISTINCT
DOMAIN
DOUBLE
DROP
ELSE
END
END-EXEC
ESCAPE
EXCEPT
EXCEPTION
EXEC
EXECUTE
EXISTS
EXTERNAL
EXTRACT
FALSE
FETCH
FIRST
FLOAT
FOR
FOREIGN
FOUND
FROM
FULL
GET
GLOBAL
GO
GOTO
GRANT
GROUP
HAVING
HOUR
IDENTITY
IMMEDIATE
IN
INDICATOR
INITIALLY
INNER
INPUT
INSENSITIVE
INSERT
INT
INTEGER
INTERSECT
INTERVAL
INTO
IS
ISOLATION
JOIN
KEY
LANGUAGE
LAST
447
LEADING
LEFT
LEVEL
LIKE
LOCAL
LOWER
MATCH
MAX
MIN
MINUTE
MODULE
MONTH
NAMES
NATIONAL
NATURAL
NCHAR
NEXT
NO
NOT
NULL
NULLIF
NUMERIC
OCTET_LENGTH
OF
ON
ONLY
OPEN
OPTION
OR
ORDER
OUTER
OUTPUT
OVERLAPS
PAD
PARTIAL
POSITION
PRECISION
PREPARE
PRESERVE
PRIMARY
PRIOR
PRIVILEGES
PROCEDURE
PUBLIC
READ
REAL
REFERENCES
RELATIVE
RESTRICT
REVOKE
RIGHT
ROLLBACK
ROWS
SCHEMA
SCROLL
SECOND
SECTION
SELECT
SESSION
SESSION_USER
SET
SMALLINT
SOME
SPACE
SQL
SQLCODE
SQLERROR
SQLSTATE
SUBSTRING
SUM
SYSTEM_USER
TABLE
TEMPORARY
THEN
TIME
TIMESTAMP
TIMEZONE_HOUR
TIMEZONE_MINUTE
TO
TRAILING
TRANSACTION
TRANSLATE
TRANSLATION
TRIM
TRUE
UNION
UNIQUE
UNKNOWN
UPDATE
UPPER
USAGE
USER
USING
VALUE
VALUES
VARCHAR
VARYING
VIEW
WHEN
WHENEVER
WHERE
WITH
WORK
WRITE
YEAR
ZONE
448
If you want to convert the date to its original format, use the DateFormat function and apply the "mm/dd/yy" mask.
2 Query of Queries is less efficient for joins in which the predicate contains multiple expressions, for example:
SELECT T1.a, b, c, d FROM T1, T2
WHERE T1.a = T2.a AND T1.b + T1.c = T2.b + T2.c
Column comparisons
Queries passed by reference
Complex objects
Comparing columns with different data types
Starting with ColdFusion MX 7, ColdFusion includes enhancements that allow you to compare columns with different
data types.
If one of the operands has a known column type (only constants have an unknown column type), Query of Queries
tries to coerce the constant with an unknown type to the type of the operand with metadata. The pairs of allowed
coercions are as follows:
Binary, string
Dates, string
Numeric, bigdecimal
Boolean, numeric
That is, ColdFusion can coerce between binary and string, but not between date and string.
If both operands have known data types, the types must be the same. The only exception is that ColdFusion can coerce
among integer, float, and double.
If both operands are constants, ColdFusion tries to coerce the values, first to the most restrictive type, then to the least
restrictive type.
449
About LDAP
The LDAP protocol enables organizations to arrange and access directory information in a hierarchy. In this context,
directory refers to a collection of information, such as a telephone directory, not a collection of files in a folder on a
disk drive.
LDAP originated in the mid-1990s as a response to the need to access ISO X.500 directories from computers that had
limited processing power. Since then, products such as iPlanet Server have been developed that are native LDAP
directory servers. Several companies now provide LDAP access to their directory servers, including Novell NDS,
Microsoft Active Directory Services (ADS), Lotus Domino, and Oracle.
An LDAP directory is typically a hierarchically structured database. Each layer in the hierarchy typically corresponds
to a level of organizational structure.
450
Root
USA
Country
Ferrari
Adobe
Organization
Unit
Italy
R&D
Sales
Ben
Jack
Sales
R&D
Gina
Individual
Laura
Amy
Sophia
Marco
Enzo
This example is fully symmetrical: all the entries at each layer are of the same type.
You can also structure an LDAP directory so that the layers under one entry contain different information from the
layers under another entry.
The following image shows such an asymmetric directory:
airius.com
people
groups
Bruce
Laura
Ben
Amy
HR
Managers
Directory
Managers
QA
Managers
Accounting
Managers
In this directory structure, the second level of the tree divides the directory into two organizational units: people and
groups. The third level contains entries with information that is specific to the organizational unit. Each persons entry
includes a name, e-mail address, and telephone number. Each groups entry includes the names of group members.
451
This complexity and flexibility is a key to the usefulness. of LDAP. With it, you can represent any organizational
structure.
LDAP offers performance advantages over conventional databases for accessing hierarchical, directory-like
information that is read frequently, and changed infrequently.
Although LDAP is often used for e-mail, address, telephone, or other organizational directories, it is not limited to
these types of applications. For example, you can store ColdFusion Advanced Security information in an LDAP
database.
Entry
Attribute
Distinguished name (DN)
Schema, including the object class and attribute type
Entry
The basic information object of LDAP is the entry. An entry is composed of one or more attributes. Entries are subject
to content rules defined by the directory schema (see Schema on page 452).
Each node, not just the terminal nodes, of an LDAP directory is an entry. In the preceding images, each item is an entry.
For example, in the first diagram, both USA and Ferrari are entries. The USA entrys attributes could include a
Language attribute, and the Ferrari entry could include an entry for the chief executive officer.
Attribute
An LDAP directory entry consists of one or more attributes. Attributes have types and values. The type determines the
information that the values can contain. The type also specifies how the value is processed. For example, the type
determines whether an attribute can have multiple values. The mail attribute type, which contains an e-mail address,
is multivalued so you can store multiple e-mail addresses for one person.
Some commonly used attribute types have short keyword type names. Often these short keyword type names
correspond to longer type names, and the two names can be used interchangeably. The following table lists common
attribute type keywords used in LDAP directories:
Keyword
Long name
CountryName
st
stateOrProvinceName
LocalityName
street
StreetAddress
OrganizationName
ou
OrganizationalUnitName
cn
CommonName
Comment
452
Keyword
Long name
sn
SurName
dc
domaincomponent
Comment
E-mail address
Schema
The concepts of schemas and object classes are central to a thorough understanding of LDAP. The information
provided here does not have detailed descriptions but is enough to use the cfldap tag effectively.
A directory schema is a set of rules that determines what can be stored in a directory. It defines, at a minimum, the
following two basic directory characteristics:
453
If an entry belongs to a class that derives from another class, the entrys objectclass attribute lists the lowest-level class
and all the superior classes from which the lowest-level class derives.
When you add, modify, or delete a directory entry, you must treat the entrys object class as a possibly multivalued
attribute. For example, when you add a new entry, you specify the object class in the cfldap tag attributes attribute.
To retrieve an entrys object class names, specify objectclass in the list of query attributes. To retrieve entries that
provide a specific type of information, you can use the object class name in the cfldap tag filter attribute.
Attribute type
The attribute type specification of a schema defines the following properties:
Create Internet White Pages so users can locate people and resources and get information about them.
Provide a front end to manage and update directory entries.
Build applications that incorporate data from directory queries in their processes.
Integrate applications with existing organizational or corporate directory services.
The cfldap tag action attribute supports the following operations on LDAP directories:
Action
Description
query
add
delete
modify
modifyDN
The following table lists the attributes that are required and optional for each action. For more information on each
attribute, see the cfldap tag in the CFML Reference.
454
Action
Required attributes
Optional attributes
query
add
delete
server, dn
modify
modifyDN
Scope
The search scope sets the limits of a search. The default scope is the level below the distinguished name specified in the
start attribute. This scope does not include the entry identified by the start attribute. For example, if the start
attribute is ou=support, o=adobe the level below support is searched. You can restrict a query to the level of the
start entry, or extend it to the entire subtree below the start entry.
Search filter
The search filter syntax has the form attribute operator value. The default filter, objectclass=*, returns all entries in the
scope.
The following table lists the filter operators:
Operator
Example
Matches
=*
(mail=*)
(o=adobe)
~=
(sn~=Hansen)
Entries with a surname that approximates Hansen. The matching rules for approximate
matches vary among directory vendors, but anything that sounds like the search string
should be matched. In this example, the directory server might return entries with the
surnames Hansen and Hanson.
>=
(st>=ma)
The name ma and names appearing after ma in an alphabetical state attribute list.
<=
(st<=ma)
The name ma and names appearing before ma in an alphabetical state attribute list.
(o=macro*)
(o=*media)
(o=mac*ia)
Organization names that start with mac and end with ia. You can use more than one *
operator in a string; for example, m*ro*dia.
(o=*med*)
Organization names that contain the string med, including the exact string match med.
455
Operator
Example
Matches
&
(&(o=adobe)
Entries in which the organization name is adobe and the country is usa.
(co=usa))
|
(|(o=adobe)
(sn=adobe)
Entries in which the organization name is adobe or the surname is adobe, or the common
name is adobe.
(cn=adobe))
!
(!(STREET=*))
The Boolean operators & and | can operate on more than two attributes and precede all of the attributes on which they
operate. You surround a filter with parentheses and use parentheses to group conditions.
If the pattern that you are matching contains an asterisk, left parenthesis, right parenthesis, backslash, or NUL
character, use the following three-character escape sequence in place of the character:
Character
Escape sequence
\2A
\28
\29
\5C
NUL
\00
For example, to match the common name St*r Industries, use the filter:
(cn=St\2Ar Industries).
LDAP v3 supports an extensible match filter that permits server-specific matching rules. For more information on
using extensible match filters, see your LDAP server documentation.
Searching and sorting notes
To search for multiple values of a multivalued attribute type, use the & operator to combine expressions for each
attribute value. For example, to search for an entry in which cn=Robert Jones and cn=Bobby Jones, specify the
following filter:
filter="(&(cn=Robert Jones)(cn=Bobby Jones))"
You can use object classes as search filter attributes; for example, you can use the following search filter:
filter="(objectclass=inetorgperson)"
To specify how query results are sorted, use the sort field to identify the attribute(s) to sort. By default, ColdFusion
returns sorted results in case-sensitive ascending order. To specify descending order, case-insensitive sorting, or
both, use the sortControl attribute.
ColdFusion requests the LDAP server to do the sorting. Doing so can have the following effects:
The sort order can differ between ColdFusion MX and previous versions.
If you specify sorting and the LDAP server does not support sorting, ColdFusion generates an error. To sort
results from servers that do not support sorting, use a query of queries on the results.
456
Using filter operators to construct sophisticated search criteria can degrade performance if the LDAP server is slow
to process the synchronous search routines that cfldap supports. Use the cfldap tag timeout and maxRows
attributes to control the apparent performance of pages that perform queries, by limiting the number of entries and
by exiting the query if the server does not respond in a specified time.
This tag returns entries for all the people in the organization and entries for all the groups. The group entries have a
different object class, and therefore different attributes from the person entries. If ColdFusion returned both types of
entries in one query object, some rows would have only the group-specific attribute values and the other rows would
have only person-specific attribute values. Instead, ColdFusion returns a structure in which each attribute is an entry.
457
458
</tr>
<tr>
<th>Name</th>
<th>Department</th>
<th>E-Mail</th>
<th>Phone</th>
</tr>
<cfoutput query="results">
<tr>
<td>#cn#</td>
<td>#listFirst(ou)#</td>
<td><a href="mailto:#mail#">#mail#</a></td>
<td>#telephonenumber#</td>
</tr>
</cfoutput>
</table>
</cfif>
</body>
</html>
2 Change the server attribute from ldap.airius.com to the name of your installation of the Airius database.
3 Save the page as cfldap.cfm and run it in your browser.
Description
459
Code
Description
Ensures that the user has submitted the form. This is necessary because the
form page is also the action page. Ensures that the user entered search text.
<cfldap
server="ldap.airius.com"
action="query"
name="results"
start="ou=People, o=Airius.com"
scope="onelevel"
filter="(&(cn=*#form.Name#*)(l=Santa
Clara))"
attributes="cn,sn,ou,mail,telephonenumber"
sort="ou,sn"
maxrows=100
timeout=20000
>
This search shows the use of a logical AND statement in a filter. It returns one attribute, the surname, that is used only
for sorting the results.
In this query, the ou attribute value consists of two values in a comma-delimited list. One is the department name. The
other is People. This is because the Airius database uses the ou attribute type twice:
In the distinguished names, at the second level of the directory tree, where it differentiates between organizational
units such as people, groups, and directory servers
Add
Delete
Last updated 1/20/2012
460
Add attributes
Delete attributes
Replace attributes
Change the DN (rename the entry)
These actions let you manage LDAP directory contents remotely.
You build a ColdFusion page that lets you manage an LDAP directory. The form displays directory entries in a table
and includes a button that lets you populate the form fields based on the unique user ID.
The example ColdFusion page does not add or delete entry attributes or change the DN. For information on these
operations, see Adding and deleting attributes of a directory entry on page 467 and Changing a directory entrys
DN on page 468.
To keep the code short, this example has limitations that are not appropriate in a production application. In particular,
it has the following limitations:
If you enter an invalid user ID and click either the Update or the Delete button, ColdFusion generates a No such
object error, because there is no directory entry to update or delete. Your application should verify that the ID
exists in the directory before it tries to change or delete its entry.
If you enter a valid user ID in an empty form and click Update, the application deletes all the attributes for the User.
The application should ensure that all required attribute fields contain valid entries before updating the directory.
461
organizationalperson, inetOrgPerson;
cn=#Trim(Form.fullName)#; sn=#Trim(Form.surname)#;
mail=#Trim(Form.email)#;
telephonenumber=#Trim(Form.phone)#;
ou=Human Resources;
uid=#Trim(Form.uid)#">
<cfldap action="add"
attributes="#attributeList#"
dn="uid=#Trim(Form.uid)#, ou=People, o=Airius.com"
server=#myServer#
username=#myUserName#
password=#myPassword#>
<cfoutput><h3>Entry for User ID #Form.uid# has been added</h3>
</cfoutput>
</cfif>
</cfif>
</cfif>
<html>
<head>
<title>Update LDAP Form</title>
</head>
<body>
<h2>Manage LDAP Entries</h2>
<cfform action="update_ldap.cfm" method="post">
<table>
<tr><td>Full Name:</td>
<td><cfinput type="Text"
name="fullName"
value=#fullNameValue#
size="20"
maxlength="30"
tabindex="1"></td>
</tr>
<tr><td>Surname:</td>
<td><cfinput type="Text"
name="surname"
Value= "#surnameValue#"
size="20"
maxlength="20"
tabindex="2"></td>
</tr>
<tr>
<td>E-mail Address:</td>
<td><cfinput type="Text"
name="email"
value="#emailValue#"
size="20"
maxlength="20"
tabindex="3"></td>
</tr>
<tr>
<td>Telephone Number:</td>
<td><cfinput type="Text"
name="phone"
value="#phoneValue#"
462
size="20"
maxlength="20"
tabindex="4"></td>
</tr>
<tr>
<td>User ID:</td>
<td><cfinput type="Text"
name="uid"
value="#uidValue#"
size="20"
maxlength="20"
tabindex="5"></td>
</tr>
<tr>
<td colspan="2">
<input type="Submit"
name="action"
value="Add"
tabindex="8"></td>
</tr>
</table>
<br>
*All fields are required for Add<br>
</cfform>
<!---Output the user list. --->
<h2>User List for the Human Resources Department</h2>
<cfldap name="GetList"
server=#myServer#
action="query"
attributes="cn,sn,mail,telephonenumber,uid"
start="o=Airius.com"
scope="subtree"
filter="ou=Human Resources"
sort="sn,cn"
sortControl="asc, nocase">
<table border="1">
<tr>
<th>Full Name</th>
<th>Surname</th>
<th>Mail</th>
<th>Phone</th>
<th>UID</th>
</tr>
<cfoutput query="GetList">
<tr>
<td>#GetList.cn#</td>
<td>#GetList.sn#</td>
<td>#GetList.mail#</td>
<td>#GetList.telephonenumber#</td>
<td>#GetList.uid#</td>
</tr>
</cfoutput>
</table>
</body>
</html>
463
2 At the top of the file, change the myServer, myUserName, and myPassword variable assignments to values that are
Description
<cfset myServer="ldap.myco.com">
<cfset myUserName="cn=Directory Manager">
<cfset myPassword="password">
Initializes the LDAP connection information variables. Uses variables for all
connection information so that any changes have to be made in only one
place.
<cfparam
<cfparam
<cfparam
<cfparam
<cfparam
Sets the default values of empty strings for the form field value variables.
The data entry form uses cfinput fields with value attributes so that the
form can be prefilled and so that, if the user submits an incomplete form,
ColdFusion can retain any entered values in the form when it redisplays
the page.
name="fullNameValue" default="">
name="surnameValue" default="">
name="emailValue" default="">
name="phoneValue" default="">
name="uidValue" default="">
If any field in the submitted form is blank, display a message and set the
other form fields to display data that the user submitted.
<cfelse>
<cfset attributelist="objectclass=top, person,
organizationalperson, inetOrgPerson;
cn=#Trim(Form.fullName)#;
sn=#Trim(Form.surname)#;
mail=#Trim(Form.email)#;
telephonenumber=#Trim(Form.phone)#; ou=Human
Resources; uid=#Trim(Form.uid)#">
If the user entered data in all fields, sets the attributelist variable to specify
the entrys attributes, including the object class and the organizational
unit (in this case, Human Resources).
<cfldap action="add"
attributes="#attributeList#"
dn="uid=#Trim(Form.uid)#, ou=People,
o=Airius.com" server=#myServer#
username=#myUserName# password=#myPassword#>
<cfoutput>
<h3>Entry for User ID #Form.uid# has been
added</h3>
</cfoutput>
</cfif>
</cfif>
</cfif>
The Trim function removes leading or trailing spaces from the user data.
464
Code
Description
<cffo
rm action="update_ldap.cfm"
method="post">
<table>
<tr>
<td>Full Name:</td>
<td><cfinput type="Text"
name="fullName"
value=#fullNameValue#
size="20"
maxlength="30"
tabindex="1"></td>
</tr>
Outputs the data entry form, formatted as a table. Each cfinput field
always has a value, set by the value attribute when the page is called. The
value attribute lets ColdFusion update the form contents when the form
is redisplayed after the user clicks Add. The code that handles cases in
which the user fails to enter all the required data uses this feature.
.
.
<tr>
<td colspan="2">
<input type="Submit"
name="action"
value="Add"
tabindex="8"></td>
</tr>
</table>
<br>
*All fields are required for Add<br>
</cfform>
<cfldap name="GetList"
server=#myServer#
action="query"
attributes="cn,sn,mail,telephonenumber,uid"
start="o=Airius.com"
scope="subtree"
filter="ou=Human Resources"
sort="sn,cn"
sortControl="asc, nocase">
Queries the directory and gets the common name, surname, e-mail
address, telephone number, and user ID from the matching entries.
<table border="1">
<tr>
<th>Full Name</th>
<th>Surname</th>
<th>Mail</th>
<th>Phone</th>
<th>UID</th>
</tr>
<cfoutput query="GetList">
<tr>
<td>#GetList.cn#</td>
<td>#GetList.sn#</td>
<td>#GetList.mail#</td>
<td>#GetList.telephonenumber#</td>
<td>#GetList.uid#</td>
</tr>
</cfoutput>
</table>
</body>
</html>
Searches the subtree from the entry with the DN of o=Airius.com, and
selects all entries in which the organizational unit is Human Resources.
Sorts the results by surname and then common name (to sort by last name,
then first). Sorts in default ascending order that is not case sensitive.
465
3 At the end of the code for the Add button (the input tag with Value=Add at the bottom of the form), delete the
</td> end tag.
4 After the end of the Add button input tag, add the following code:
 
<input type="Submit"
name="action"
value="Retrieve"
tabindex="7">
 
<input type="Submit"
name="action"
value="Delete"
tabindex="8"></td>
466
Code
Description
If the user clicks Retrieve, queries the directory and gets the information for the
specified User ID.
The user clicks delete, deletes the entry with the specified User ID, and informs
the user that the entry was deleted.
 
<input type="Submit"
name="action"
value="Retrieve"
tabindex="7">
 
<input type="Submit"
name="action"
value="Delete"
tabindex="8"></td>
Sets the form fields Value attribute to the corresponding query column.
This example uses the array index [1] to identify the first row of the GetEntry
query object. Because the query always returns only one row, the index can be
omitted.
3 At the end of the code for the Delete button (the input tag with Value=Delete at the bottom of the form), delete
467
4 After the end of the Delete button input tag, add the following code:
 
<input type="Submit"
name="action"
value="Update"
tabindex="9"></td>
Description
If the user clicks Update, sets the attribute list to the form field values
and replaces the attributes for the entry with the specified UID.
 
<input type="Submit"
name="action"
value="Update"
tabindex="9"></td>
cfldap syntax
dn = "entry dn"
action = "modify"
modifyType = "add"
attributes = "attribname=attribValue[;...]"
dn = "entry dn"
action = "modify"
modifyType = "delete"
attributes = "attribName[;...]"
You can add or delete multiple attributes in one statement. To do this, use semicolons to separate the attributes in the
attribute string.
The following example specifies the description and seealso LDAP attributes:
attributes="description=Senior Technical Writer;seealso=writers"
You can change the character that you use to separate values of multivalued attributes in an attribute string. You can
also change the character that separates attributes when a string contains multiple attributes. For more information,
see Specifying an attribute that includes a comma or semicolon on page 468.
You can add or delete attributes only if the directory schema defines them as optional for the entrys object class.
468
For example:
<cfldap action="modifyDN"
dn="#old_UID#, ou=People, o=Airius.com"
attributes="uid=#newUID#"
server=#myServer#
username=#myUserName#
password=#myPassword#>
The new DN and the entry attributes must conform to the directory schema; therefore, you cannot move entries
arbitrarily in a directory tree. You can only modify a leaf only. For example, you cannot modify the group name if the
group has children.
Note: LDAP v2 does not let you change entry DNs.
Advanced topics
Some more advanced techniques enable you to use LDAP directories more effectively.
469
470
thiselement = Trim(thisElement);
nameloc = Find("NAME", thisElement);
descloc = Find("DESC", thisElement);
suploc = Find("SUP", thisElement);
mustloc = Find("MUST", thisElement);
mayloc = Find("MAY", thisElement);
endloc = Len(thisElement);
</cfscript>
<tr>
<td><cfoutput>#Mid(thisElement, nameloc+6, descloc-nameloc-8)#
</cfoutput></td>
<cfif #suploc# NEQ 0>
<td><cfoutput>#Mid(thisElement, suploc+5, mustloc-suploc-7)#
</cfoutput></td>
<cfelse>
<td>NONE</td>
</cfif>
<cfif #mayloc# NEQ 0>
<td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
mayloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td>
<td><cfoutput>#Replace(Mid(thisElement, mayloc+5, endloc-mayloc-8),
" $ ", ", ", "all")#</cfoutput></td>
<cfelse>
<td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
endloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td>
<td>NONE</td>
</cfif>
</tr>
</cfloop>
</table>
<br><br>
<h2>Attribute Types</h2>
<table border="1" >
<tr>
<th>Name</th>
<th>Description</th>
<th>multivalued?</th>
</tr>
<cfloop index = "thisElement"
list = #ReplaceNoCase(EntryList2.attributeTypes, ", alias", "<br> Alias",
"all")# delimiters = ",">
<cfscript>
thiselement = Trim(thisElement);
nameloc = Find("NAME", thisElement);
471
2 Change the server from ldap.mycorp.com to your LDAP server. You might also need to specify a user ID and
472
Code
Description
<cfldap
name="EntryList"
server="ldap.mycorp.com"
action="query"
attributes="subschemaSubentry"
scope="base"
start="">
<cfldap
name="EntryList2"
server="ldap.mycorp.com"
action="query"
attributes="objectclasses, attributetypes"
scope="base"
filter="objectclass=*"
start=#entryList.subschemaSubentry#>
473
Code
Description
<h2>Object Classes</h2>
<table border="1">
<tr>
<th>Name</th>
<th>Superior class</th>
<th>Must have</th>
<th>May have</th>
</tr>
<cfloop index = "thisElement" list =
#Entrylist2.objectclasses#>
<cfscript>
thiselement = Trim(thisElement);
nameloc = Find("NAME", thisElement);
descloc = Find("DESC", thisElement);
suploc = Find("SUP", thisElement);
mustloc = Find("MUST", thisElement);
mayloc = Find("MAY", thisElement);
endloc = Len(thisElement);
</cfscript>
<tr>
<td><cfoutput>#Mid(thisElement, nameloc+6, desclocnameloc-8)#
</cfoutput></td>
<cfif #suploc# NEQ 0>
<td><cfoutput>#Mid(thisElement, suploc+5, mustlocsuploc-7)#
</cfoutput></td>
<cfelse>
<td>NONE</td>
</cfif>
<cfif #mayloc# NEQ 0>
<td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
mayloc-mustloc-9), " $ ", ", ",
"all")#</cfoutput></td>
<td><cfoutput>#Replace(Mid(thisElement, mayloc+5,
endloc-mayloc-8),
" $ ", ", ", "all")#</cfoutput></td>
<cfelse>
<td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
endloc-mustloc-9), " $ ", ", ",
"all")#</cfoutput></td>
<td>NONE</td>
</cfif>
</tr>
</cfloop>
</table>
Displays the field values. Uses the Mid function to extract individual
field values from the thisElement string.
The top object class does not have a superior class entry. Handles this
special case by testing the suploc location variable. If the value is not
0, handles normally, otherwise, output "NONE".
There might not be any optional attributes. Handles this case
similarly to the superior class. The calculation of the location of
required attributes uses the location of the optional attributes if the
field exists; otherwise, uses the end of the object class definition
string.
474
Code
Description
<h2>Attribute Types</h2>
<table border="1" >
<tr>
<th>Name</th>
<th>Description</th>
<th>multivalued?</th>
</tr>
<cfloop index = "thisElement"
list = #ReplaceNoCase(EntryList2.attributeTypes, ",
alias", "<br> Alias",
"all")# delimiters = ",">
<cfscript>
thiselement = Trim(thisElement);
nameloc = Find("NAME", thisElement);
descloc = Find("DESC", thisElement);
syntaxloc = Find("SYNTAX", thisElement);
singleloc = Find("SINGLE", thisElement);
endloc = Len(thisElement);
</cfscript>
<tr>
<td><cfoutput>#Mid(thisElement, nameloc+6, desclocnameloc-8)#
</cfoutput></td>
<td><cfoutput>#Mid(thisElement, descloc+6,
syntaxloc-descloc-8)#
</cfoutput></td>
<cfif #singleloc# EQ 0>
<td><cfoutput>Yes</cfoutput></td>
<cfelse>
<td><cfoutput>No</cfoutput></td>
</cfif>
</tr>
</cfloop>
Does the same types of calculations for the attribute types as for the
object classes.
The attribute type field can contain the text ", alias for....". This text
includes a comma, which also delimits attribute entries. Use the
REReplaceNoCase function to replace any comma that precedes the
word "alias" with an HTML <br> tag.
Referrals
An LDAP database can be distributed over multiple servers. If the requested information is not on the current server,
the LDAP v3 standard provides a mechanism for the server to return a referral to the client that informs the client of
an alternate server. (This feature is also included in some LDAP v2-compliant servers.)
ColdFusion can handle referrals automatically. If you specify a nonzero referral attribute in the cfldap tag,
ColdFusion sends the request to the server specified in the referral.
The referral attribute value specifies the number of referrals allowed for the request. For example, if the referral
attribute is 1, and server A sends a referral to server B, which then sends a referral to server C, ColdFusion returns an
error. If the referral attribute is 2, and server C has the information, the LDAP request succeeds. The value to use
depends on the topology of the distributed LDAP directory, the importance of response speed, and the value of
response completeness.
When ColdFusion follows a referral, the rebind attribute specifies whether ColdFusion uses the cfldap tag login
information in the request to the new server. The default, No, sends an anonymous login to the server.
475
The keytool utility initial keypass password is change it. For more information on using the keytool utility, see the
Sun JDK documentation.
Once ColdFusion establishes secure communication with the server, it must provide the server with login credentials.
You specify the login credentials in the cfldap tag username and password attributes. When the server determines
that the login credentials are valid, ColdFusion can access the directory.
Using LDAP security
To use security, first ensure that the LDAP server supports SSL v2 security.
Specify the cfldap tag secure attribute as follows:
secure = "cfssl_basic"
For example:
<cfldap action="modify"
modifyType="add"
atributes="cn=Lizzie"
dn="uid=lborden, ou=People, o=Airius.com"
server=#myServer#
username=#myUserName#
password=#myPassword#
secure="cfssl_basic"
port=636>
The port attribute specifies the server port used for secure LDAP communications, which is 636 by default. If you do
not specify a port, ColdFusion attempts to connect to the default, nonsecure, LDAP port 389.
Application security
To ensure application security, prevent outsiders from gaining access to the passwords that you use in cfldap tags. The
best way to do this is to use variables for your username and password attributes. You can set these variables on one
encrypted application page. For more information on securing applications, see Securing Applications on page 339.
476
About Verity
To efficiently search through paragraphs of text or files of varying types, you need full-text search capabilities.
ColdFusion includes the Verity search engine, which provides full-text indexing and searching.
The Verity engine performs searches against collections, not against the actual documents. A collection is a special
database created by Verity that contains metadata that describes the documents that you have indexed. The indexing
process examines documents of various types in a collection and creates a metadata descriptionthe indexwhich is
specialized for rapid search and retrieval operations.
The ColdFusion implementation of Verity supports collections of the following basic data types:
Index your website and provide a generalized search mechanism, such as a form interface, for executing searches.
Index specific directories that contain documents for subject-based searching.
Index specific categories of documents. By organizing your documents into categories, you can let users search
specific types of documents. For example, if your website contains FAQs, documentation, and tutorials, you can
create a search that lets users search within each of these categories.
Index cfquery recordsets, giving users the ability to search against the data. Because collections contain data
optimized for retrieval, this method is much faster than performing multiple database queries to return the same data.
Index e-mail generated by ColdFusion application pages and create a searching mechanism for the indexed
messages.
477
Build collections of inventory data and make those collections available for searching from your ColdFusion
application pages.
Support international users in a range of languages using the cfindex, cfcollection, and cfsearch tags.
You can reduce the programming overhead of query constructs by allowing users to construct their own queries
and execute them directly. You need to be concerned only with presenting the output to the client web browser.
Verity can index database text fields, such as notes and product descriptions, that native database tools cannot
effectively index.
When indexing collections that contain documents in formats such as Adobe Acrobat (PDF) and Microsoft Word,
Verity scans for the document title (if one was entered), in addition to the document text, and displays the title in
the search results list.
When Verity indexes web pages, it can return the URL for each document. This is a valuable document
management feature.
For more information, see Indexing data returned by a query on page 497.
Format
Version(s)
ANSI (TXT)
All versions
ASCII (TXT)
All versions
HTML (HTM)
SC23-0758-1
1 through 1.6
3, 4
478
Document format
Format
Version(s)
Word processing
5, 5.5, 6, 7
DisplayWrite (IP)
3.1
8, 9, 10, 12
2, 3
4, 5, 5.5, 6
1 through 2002
4, 5, 6, 98
1 through 2000
1, 2, 3
5, 5.1
6, 7, 8, 10, 2000
XyWrite (XY4)
4.12
No specific version
5, 6, 7, 8
2, 3, 4, 5
2, 3, 4, 5
98
2, 3, 4, 5, 6, 7
1, 2, 3, 4
Spreadsheet formats
479
Document format
Format
Version(s)
Presentation formats
98
Display formats
Graphics formats
supported for indexing
No specific version
No specific version
No specific version
Multimedia formats
Container formats
DynaZIP
No specific version
PKZIP (zip)
WinZIP
No specific version
No specific version
E-mail formats
Specifying a language
If you install the optional ColdFusion International Search pack, you can specify a language other than English when
creating a collection.
ColdFusion supports Verity Locales in European, Asian, and Middle Eastern languages. For more information about
installing Verity Locales, see Installing ColdFusion.
For English language support, Verity provides two options: English (Basic) and English (Advanced). The default
language for Verity collections is English (Basic). Indexing a collection using English (Basic) is faster than using
English (Advanced), however, English (Advanced) provides better search results.
480
Specify a language when you create the collection. The language you specify should match the language the documents
were authored in. By specifying the language your documents are written in, Verity is able to correctly interpret accented
characters, and, in many languages, use variations of word stems and roots. However, Verity does not support the
following in Eastern European and Middle Eastern languages, including these languages in the Universal language pack:
Stemming
Normalization
Decomposition of compound words into subwords
Part of speech
Special number handling
If you have documents in several languages, create separate collections for each of them.
To specify a language when you are indexing data, select the language from the pop-up menu when you create a
collection with the ColdFusion Administrator. In CFML, the cfcollection, cfindex, and cfsearch tags have an
optional language attribute that you use to specify the language of the collection.
Use the following table to find the correct value for the language attribute for your collection. For example, the
following code creates a collection for simplified Chinese:
<cfcollection action = "create" collection = "lei_01"
path = "c:\CFusion\verity\collections"
language = "simplified_chinese">
The following table lists the languages names and attributes that ColdFusion supports:
Language
Language attribute
Arabic
arabic
Chinese (simplified)
simplified_chinese
Chinese (traditional)
traditional_chinese
Czech
czech
Danish
danish
Dutch
dutch
English (Basic)
english
English (Advanced)
englishx
Finnish
finnish
French
french
German
german
Greek
greek
Hebrew
hebrew
Hungarian
hungarian
Italian
italian
Japanese
japanese
Korean
korean
481
Language
Language attribute
Norwegian
norwegian
Norwegian (Bokmal)
bokmal
Norwegian (Nynorsk)
nynorsk
Polish
polish
Portuguese
portuguese
Russian
russian
Spanish
spanish
Swedish
swedish
Turkish
turkish
Multiple languages
uni
You can register collections in the ColdFusion Administrator or by creating a collection with the cfcollection tag.
If you register a given collection with ColdFusion and you specify a language attribute, you do not have to specify the
language attribute when using cfindex and cfsearch tags for that collection. If you do not register a given collection
with ColdFusion, ColdFusion uses English (Basic), the default language, unless you specify the language in the
language attribute for the cfindex and cfsearch tags for that collection.
Note: When you search a collection in a language other than English, translate operators such as AND and OR into the
language of the collection.
You can perform each task programmaticallythat is, by writing CFML code. Alternatively, you can use the
ColdFusion Administrator to create and index a collection.
By default in the server configuration, ColdFusion stores collections in cf_root\verity\collections\ in Windows and
in cf_root/verity/collections on UNIX. In the multiserver configuration, the default location for collections is
cf_webapp_root/verity/collections. In the J2EE configuration, the default location for collections is
verity_root/verity/collections, where verity_root is the directory in which you installed Verity.
Note: This is the location for the collection, not for the files that you search.
4 (Optional) Select a language other than English for the collection from the Language drop-down list.
482
For more information on selecting a language, see Specifying a language on page 479.
5 (Optional) Select Enable Category Support to create a Verity Parametric collection.
For more information on using categories, see Narrowing searches by using categories on page 492.
6 Click Create Collection.
The name and full path of the new collection appears in the list of Verity Collections.
You have successfully created an empty collection. A collection becomes populated with data when you index it.
You can use cfcollectionaction="optimize" if you notice that searches on a collection take longer than they did
previously.
Updating an index
Documents are modified frequently in many user environments. After you index your documents, any changes that
you make are not reflected in subsequent Verity searches until you reindex the collection. Depending on your
environment, you can create a scheduled task to automatically keep your indexes current. For more information on
scheduled tasks, see Configuring and Administering ColdFusion.
You want your ColdFusion application to be able to create, delete, and maintain a collection.
483
Description
action
(Optional) The action to perform on the collection (create, delete, or optimize). The default value for the action
attribute is list. For more information, see cfcollection in CFML Reference.
collection
The name of the new collection, or the name of a collection upon which you perform an action.
path
language
The language.
categories
(Optional) Specifies that cfcollection create a Verity Parametric Index (PI) for this collection. By default, the
categories attribute is set to False. To create a collection that uses categories, specify Yes.
You can create a collection by directly assigning a value to the collection attribute of the cfcollection tag, as
shown in the following code:
<cfcollection action = "create"
collection = "a_new_collection"
path = "c:\CFusion\verity\collections\">
If you want your users to be able to dynamically supply the name and location for a new collection, use the following
procedures to create form and action pages.
Create a simple collection form page
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>Collection Creation Input Form</title>
</head>
<body>
<h2>Specify a collection</h2>
<form action="collection_create_action.cfm" method="POST">
<p>Collection name:
<input type="text" name="CollectionName" size="25"></p>
<p>What do you want to do with the collection?</p>
<input type="radio"
name="CollectionAction"
value="Create" checked>Create<br>
<input type="radio"
name="CollectionAction"
value="Optimize">Optimize<br>
<input type="submit"
name="submit"
value="Submit">
</form>
</body>
</html>
484
2 Save the file as collection_create_form.cfm in the myapps directory under the web root directory.
Note: The form does not work until you write an action page for it, which is the next procedure.
Create a collection action page
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>cfcollection</title>
</head>
<body>
<h2>Collection creation</h2>
<cfoutput>
<cfswitch expression=#Form.collectionaction#>
<cfcase value="Create">
<cfcollection action="Create"
collection="#Form.CollectionName#"
path="c:\CFusion\verity\collections\">
<p>The collection #Form.CollectionName# is created.</p>
</cfcase>
<cfcase value="Optimize">
<cfcollection action="Optimize"
collection="#Form.CollectionName#">
<p>The collection #Form.CollectionName# is optimized.</p>
</cfcase>
<cfcase value="Delete">
<cfcollection action="Delete"
collection="#Form.CollectionName#">
<p>The collection is deleted.</p>
</cfcase>
</cfswitch>
</cfoutput>
</body>
</html>
2 Save the file as collection_create_action.cfm in the myapps directory under the web root directory.
3 In the web browser, enter the following URL to display the form page:
http://hostname:portnumber/myapps/collection_create_form.cfm
4 Enter a collection name; for example, CodeColl.
5 Verify that Create is selected and submit the form.
6 (Optional) In the ColdFusion Administrator, reload the ColdFusion Collections page.
The name and full path of the new collection appear in the list of Verity Collections.
You successfully created a collection, named CodeColl, that currently has no data.
485
Description
collection
action
Specifies what the cfindex tag should do to the collection. The default action is to update the collection,
which generates a new index. Other actions are to delete, purge, or refresh the collection.
type
Specifies the type of files or other data to which the cfindex tag applies the specified action. The value you
assign to the type attribute determines the value to use with the key attribute (see the following list). When you
enter a value for the type attribute, cfindex expects a corresponding value in the key attribute. For example,
if you specify type=file, cfindex expects a directory path and filename for the key attribute.
The type attribute has the following possible values:
file: Specifies a directory path and filename for the file that you are indexing.
path: Specifies a directory path that contains the files that you are indexing.
extensions
(Optional) The delimited list of file extensions that ColdFusion uses to index files if type="path".
key
The value that you specify for the key attribute depends on the value set for the type attribute:
URLpath
If type="file", the key is the directory path and filename for the file you are indexing.
If type="path", the key is the directory path that contains the files you are indexing.
If type="custom", the key is a unique identifier specifying the location of the documents you are indexing;
for example, the URL of a specific web page or website whose contents you want to index. If you are indexing
data returned by a query (from a database for example), the key is the name of the recordset column that
contains the primary key.
(Optional) The URL path for files if type="file" and type="path". When the collection is searched with the
cfsearch tag, ColdFusion works as follows:
type="path": The path name is automatically prefixed to filenames and returned as the URLpath attribute.
recurse
(Optional) Yes or No. If type = "path" , Yes specifies that directories below the path specified in the key
attribute are included in the indexing operation.
language
(Optional) The language of the collection. The default language is English Basic.
To learn more about support for languages, see Specifying a language on page 479.
You can use form and action pages like the following examples to select and index a collection.
Select which collection to index
1 Create a ColdFusion page with the following content:
486
<html>
<head>
<title>Select the Collection to Index</title>
</head>
<body>
<h2>Specify the index you want to build</h2>
<form method="Post" action="collection_index_action.cfm">
<p>Enter the collection you want to index:
<input type="text" name="IndexColl" size="25" maxLength="35"></p>
<p>Enter the location of the files in the collection:
<input type="text" name="IndexDir" size="50" maxLength="100"></p>
<p>Enter a Return URL to prepend to all indexed files:
<input type="text" name="urlPrefix" size="80" maxLength="100"></p>
<input type="submit" name="submit" value="Index">
</form>
</body>
</html>
2 Save the file as collection_index_form.cfm in the myapps directory under the web_root.
Note: The form does not work until you write an action page for it, which you do when you index a collection.
Use cfindex to index a collection
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>Creating Index</title>
</head>
<body>
<h2>Indexing Complete</h2>
<cfindex collection="#Form.IndexColl#"
action="refresh"
extensions=".htm, .html, .xls, .txt, .mif, .doc"
key="#Form.IndexDir#"
type="path"
urlpath="#Form.urlPrefix#"
recurse="Yes"
language="English">
<cfoutput>
The collection #Form.IndexColl# has been indexed.
</cfoutput>
</body>
</html>
http://hostname:portnumber/myapps/collection_index_form.cfm
4 Enter a collection name; for example, CodeColl.
487
server).
7 Click Index.
C:\Inetpub\wwwroot\vw_files.
5 (Optional) To extend the indexing operation to all directories below the selected path, select the Recursively index
This step lets you create a link to any of the files in the index; for example, http://127.0.0.1/vw_files/.
7 (Optional) Select a language other than English.
cfsearch
Searches a collection
488
cfquery
cfsearch
Note: You receive an error if you attempt to search a collection that has not been indexed.
The following are important attributes for the cfsearch tag:
Attribute
Description
name
collection
The name of the collection(s) being searched. Separate multiple collections with a comma; for example,
collection = "sprocket_docs,CodeColl".
criteria
maxrows
The maximum number of records returned by the search. Always specify this attribute to ensure optimal
performance (start with 300 or less, if possible).
Each cfsearch returns variables that provide the following information about the search:
Attribute
Description
RecordCount
CurrentRow
RecordsSearched
The total number of records in the index that were searched. If no records are returned in the search, this
property returns a null value.
Summary
Context
A context summary that contains the search terms, highlighted in bold (by default). This is enabled if you
set the contextpassages attribute to a number greater than zero.
Additionally, if you specify the status attribute, the cfsearch tag returns the status structure, which contains the
information in the following table:
Variable
Description
found
searched
The number of documents searched. Corresponds to the recordsSearched column in the search results.
time
The number of milliseconds the search took, as reported by the Verity K2 search service.
suggestedQuery
An alternative query, as suggested by Verity, that may produce better results. This often contains corrected
spellings of search terms. Present only when the suggestions tag attribute criteria is met.
Keywords
A structure that contains each search term as a key to an array of up to five possible alternative terms in order
of preference. Present only when the suggestions tag attribute criteria is met.
You can use search form and results pages like the following examples to search a collection.
489
<html>
<head>
<title>Searching a collection</title>
</head>
<body>
<h2>Searching a collection</h2>
<form method="post" action="collection_search_action.cfm">
<p>Enter search term(s) in the box below. You can use AND, OR, NOT, and
parentheses. Surround an exact phrase with quotation marks.</p>
<p><input type="text" name="criteria" size="50" maxLength="50">
</p>
<input type="submit" value="Search">
</form>
</body>
</html>
Enter search target words in this form, which ColdFusion passes as the variable criteria to the action page, which
displays the search results.
490
Note: As part of the indexing process, Verity automatically produces a summary of every document file or every query
recordset that gets indexed. The default summary result set column selects the best sentences, based on internal rules, up
to a maximum of 500 characters. Every cfsearch operation returns summary information by default. For more
information, see Using Verity Search Expressions on page 505. Alternatively, you can use the context result set column,
which provides a context summary with highlighted search terms.
Description
ContextHighlightBegin
Specifies the HTML tag to prefix to the search term within the returned documents. This attribute
must be used in conjunction with ContextHighlightEnd to highlight the resulting search terms. The
default HTML tag is <b>, which highlights search terms using bold type.
ContextHighlightEnd
Specifies the HTML tag to append to the search term within the returned documents.
ContextPassages
The number of passages/sentences Verity returns in the context summary (the context column of
the results). The default value is 0; this disables the context summary.
ContextBytes
The total number of bytes that Verity returns in the context summary. The default is 300 bytes.
The following example adds to the previous search results example by highlighting the returned search terms with bold
type.
Create a search results page that includes term highlighting
1 Create a ColdFusion page with the following content:
491
<html>
<head>
<title>Search Results</title>
</head>
<body>
<cfsearch
name = "codecoll_results"
collection = "CodeColl"
criteria = "#Form.Criteria#"
ContextHighlightBegin="<b>"
ContextHighlightEnd="</b>"
ContextPassages="1"
ContextBytes="500"
maxrows = "100">
<h2>Search Results</h2>
<cfoutput>
Your search returned #codecoll_results.RecordCount# file(s).
</cfoutput>
<cfoutput query="codecoll_results">
<p>
File: <a href="#URL#">#Key#</a><br>
Document Title (if any): #Title#<br>
Score: #Score#<br>
Summary: #Summary#<br>
Highlighted Summary: #context#</p>
</cfoutput>
</body>
</html>
492
<html>
<head>
<title>Search Results</title>
</head>
<body>
<cfsearch
name = "codecoll_results"
collection = "CodeColl"
criteria = "#Form.Criteria#">
status = "info"
suggestions="5"
ContextPassages = "1"
ContextBytes = "300"
maxrows = "100">
<h2>Search Results</h2>
<cfoutput>
Your search returned #codecoll_results.RecordCount# file(s).
</cfoutput>
<cfif info.FOUND LTE 5 AND isDefined("info.SuggestedQuery")>
Did you mean:
<a href="search,cfm?query=#info.SuggestedQuery#>#info.SuggestedQuery#</a>
</cfif>
<cfoutput query="codecoll_results">
<p>
File: <a href="#URL#">#Key#</a><br>
Document Title (if any): #Title#<br>
Score: #Score#<br>
Summary: #Summary#<br>
Highlighted Summary: #context#</p>
</cfoutput>
</body>
</html>
493
2 Index the collection, specifying the category and categoryTree attributes appropriate to the collection.
For more information on indexing Verity collections with support for categories, see Indexing collections that
contain categories on page 493.
3 Create a search page that lets users search within the categories that you created.
Create a search page using the cfsearch tag that lets users more easily search for information by restricting
searches to the specified category and, if specified, its hierarchical tree.
For more information on searching Verity collections with support for categories, see Searching collections that
contain categories on page 494.
Creating collections with support for categories
You can either select Enable Category Support from the ColdFusion Administrator, or write a cfcollection tag that
uses the category attribute. By enabling category support, you create a collection that contains a Verity Parametric
Index (PI).
<cfcollection
action = "action"
collection = "collectionName"
path = "path_to_verity_collection"
language = "English"
categories = "yes">
For more information on using the cfcollection tag to create Verity collections with support for categories, see
cfcollection in the CFML Reference.
Indexing collections that contain categories
When you index a collection with support for categories enabled, do the following:
Specify a category name using the category attribute. The name (or names) that you provide identifies the
category so that users can specify searches on the documents that the collection contains. For example, you create
five categories named taste, touch, sight, sound, and smell. When performing a search, users could select from either
a pop-up menu or check box to search within one or more of the categories, thereby limiting their search within a
given range of topics.
<cfindex collection="#Form.IndexColl#"
action="update"
extensions=".htm, .html, .xls, .txt, .mif, .doc, .pdf"
key="#Form.IndexDir#"
type="path"
urlpath="#Form.urlPrefix#"
recurse="Yes"
language="English"
category="taste, touch, sight, sound, smell">
Specify a hierarchical document tree (like a file system tree) within which you can limit searches, when you use the
categoryTree attribute. With the categoryTree attribute enabled, ColdFusion limits searches to documents
494
<cfindex collection="#Form.IndexColl#"
action="update"
extensions=".htm, .html, .xls, .txt, .mif, .doc, .pdf"
key="#Form.IndexDir#"
type="path"
urlpath="#Form.urlPrefix#"
recurse="Yes"
language="English"
category="taste, touch, sight, sound, smell"
categoryTree="human/senses/taste">
For more information on using the cfindex tag to create Verity collections with support for categories, see cfindex
in the CFML Reference.
Searching collections that contain categories
When searching data in a collection created with categories, you specify category and categoryTree. The values
supplied to these attributes specify the category to be searched for the specified search string (the criteria attribute).
The category attribute can contain a comma-separated list of categories to search. Both attributes can be specified at
the same time.
<cfsearch collection="collectionName"
name="results"
maxrows = "100"
criteria="search keywords"
category="FAQ,Technote"
categoryTree="Docs/Tags">
Note: If cfsearch is executed on a collection that was created without category information, an exception is thrown.
To search collections that contain categories, you use the cfsearch tag, and create an application page that searches
within specified categories. The following example lets the user enter and submit the name of the collection, the
category in which to search, and the document tree associated with the category through a form. By restricting the
search in this way, the users are better able to retrieve the documents that contain the information they are looking for.
In addition to searching with a specified category, this example also makes use of the contextHighlight attribute,
which highlights the returned search results.
<cfparam name="collection" default="test-pi">
<cfoutput>
<form action="#CGI.SCRIPT_NAME#" method="POST">
Collection Name: <input Type="text" Name="collection" value="#collection#">
<P>
Category: <input Type="text" Name="category" value=""><br>
CategoryTree: <input Type="text" Name="categoryTree" value=""><br>
<P>
Search: <input Type="text" Name="criteria">
<input Type="submit" Value="Search">
</form>
</cfoutput>
<cfif isdefined("Form.criteria")>
<cfoutput>Search results for: <b>#criteria#</b></cfoutput>
<br>
<cfsearch collection="#form.collection#"
category="#form.category#"
categoryTree="#form.categoryTree#"
name="sr"
495
status="s"
criteria="#form.criteria#"
contextPassages="3"
contextBytes="300"
contextHighlightBegin="<i><b>"
contextHighlightEnd="</b></i>"
maxrows="100">
<cfdump var="#s#">
<cfoutput>
<p>Number of records in query: #sr.recordcount#</P>
</cfoutput>
<cfdump var="#sr#">
<cfoutput Query="sr">
Title: <i>#title#</i><br>
URL: #url#<br>
Score: #score#<br>
<hr>
#context#<br>
<br>
#summary#<br>
<hr>
</cfoutput>
</cfif>
For more information on using the cfindex tag to create Verity collections with support for categories, see cfsearch
in the CFML Reference.
Retrieving information about the categories contained in a collection
You can retrieve the category information for a collection by using the cfcollection tags categoryList action.The
categoryList action returns a structure that contains two keys:
Variable
Description
categories
The name of the category and its hit count, where hit count is the number of documents in the specified category.
categorytrees
The document tree (a/b/c) and hit count, where hit count is the number of documents at or below the branch of the
document tree.
Use the information returned by categoryList to display to users the number of documents available for searching,
as well the document tree available for searching. You can also create a search interface that lets the user select what
category to search within based on the results returned by categoryList.
<cfcollection
action="categoryList"
collection="collectionName"
name="info">
<cfoutput>
<cfset catStruct=info.categories>
<cfset catList=StructKeyList(catStruct)>
<cfloop list="catList" index="cat"> Category: #cat# <br>
Documents: #catStruct[cat]#<br>
</cfloop>
</cfoutput>
496
To retrieve information about the categories contained in a collection, you use the cfcollection tag, and create an
application page that retrieves category information from the collection and displays the number of documents
contained by each category. This example lets the user enter and submit the name of the collection via a form, and then
uses the categoryList action to retrieve information about the number of documents contained by the collection,
and the hierarchical tree structure into which the category is organized.
<html>
<head>
<title>Category information</title>
</head>
<body>
<cfoutput>
<form action="#CGI.SCRIPT_NAME#" method="POST">
Enter Collection Name: <input Type="text" Name="collection"
value="#collection#"><br>
<input Type="submit" Value="GetInfo">
</form>
</cfoutput>
<cfif isdefined("Form.collection")>
<cfoutput>
Getting collection info...
<br>
<cfflush>
<cfcollection
action="categorylist"
collection="#collection#"
name="out">
<br>
<cfset categories=out.categories>
<cfset tree=out.categorytrees>
<cfset klist=StructKeyList(categories)>
<table border=1>
<th>Category</th> <th>Documents</th>
<cfloop index="x" list="#klist#">
<tr>
<td>#x#</td> <td align="center">#categories[x]#</td>
</tr>
</cfloop>
</table>
<cfset klist=StructKeyList(tree)>
<table border=1>
<th>Category</th> <th>Documents</th>
<cfloop index="x" list="#klist#">
<tr>
<td>#x#</td> <td align="center">#tree[x]#</td>
</tr>
</cfloop>
</table>
</cfoutput>
</cfif>
</body>
For more information on using the cfcollection tag to create Verity collections with support for categories, see
cfcollection in CFML Reference.
497
Attribute values
File
The key attribute is the name of a column in the query that contains a full filename (including path).
Path
The key attribute is the name of a column in the query that contains a directory pathname.
Custom
The key attribute specifies a column name that can contain anything you want. In this case, the body attribute is
required, and is a comma-delimited list of the names of the columns that contain the text data to be indexed.
The cfindex tag treats all collections the same, whether they originate from a database recordset, or if they are a
collection of documents stored within your websites root folder.
The cfindex tag indexes the recordset as if it is a collection of documents in a folder within your website.
4 Search the collection.
The information returned from the collection includes the database key and other selected columns. You can then
use the information as-is, or use the key value to retrieve the entire row from the database table.
Use Verity to search databases in the following cases:
You want to perform full-text search on database data. You can search Verity collections that contain textual data
much more efficiently with a Verity search than using SQL to search database tables.
You want to give your users access to data without interacting directly with the data source itself.
You want to improve the speed of queries.
You want users to be able to execute queries, but not update database tables.
Unlike indexing documents stored on your web server, indexing information contained in a database requires an
additional step first write a query (using the cfquery, cfldap, or cfpop tag) that retrieves the data you want to let
your users search. You then pass the information retrieved by the query to a cfindex tag, which indexes the data.
When indexing data with the cfindex tag, specify which column of the query represents the filename, which column
represents the document title, and which column (or columns) represents the documents body (the information that
you want to make searchable).
498
When indexing a recordset retrieved from a database, the cfindex tag uses the following attributes that correspond
to the data source:
Attribute
Description
key
title
body
type
If set to custom, this attribute specifies the columns that you want to index. If set to file or path, this is a column
that contains either a directory path and filename, or a directory path that contains the documents to be indexed.
Using the cfindex tag to index tabular data is like indexing documents, with the exception that you refer to column
names from the generated recordset in the body attribute. In the following example, the type attribute is set to custom,
specifying that the cfindex tag index the contents of the recordset columns Emp_ID, FirstName, LastName, and
Salary, which are identified using the body attribute. The Emp_ID column is listed as the key attribute, making it the
primary key for the recordset.
Index a ColdFusion query
1 Create a Verity collection for the data that you want to index.
The following example assumes that you have a Verity collection named CodeColl. You can use the ColdFusion
Administrator to create the collection, or you can create the collection programmatically by using the
cfcollection tag. For more information, see Creating a collection with the ColdFusion Administrator on
page 481 or Creating a collection with the cfcollection tag on page 482.
2 Create a ColdFusion page with the following content:
499
<html>
<head>
<title>Adding Query Data to an Index</title>
</head>
<body>
<!--- Retrieve data from the table. --->
<cfquery name="getEmps" datasource="cfdocexamples">
SELECT * FROM EMPLOYEE
</cfquery>
<!--- Update the collection with the above query results. --->
<cfindex
query="getEmps"
collection="CodeColl"
action="Update"
type="Custom"
key="Emp_ID"
title="Emp_ID"
body="Emp_ID,FirstName,LastName,Salary">
<h2>Indexing Complete</h2>
<!--- Output the record set. --->
<p>Your collection now includes the following items:</p>
<cfoutput query="getEmps">
<p>#Emp_ID# #FirstName# #LastName# #Salary#</p>
</cfoutput>
</body>
</html>
3 Save the file as collection_db_index.cfm in the myapps directory under the web root directory.
4 Open the file in the web browser to index the collection.
500
<html>
<head>
<title>Searching a collection</title>
</head>
<body>
<h2>Searching a collection</h2>
<form method="post" action="collection_db_results.cfm">
<p>Collection name: <input type="text" name="collname" size="30" maxLength="30"></p>
<p>Enter search term(s) in the box below. You can use AND, OR, NOT,
and parentheses. Surround an exact phrase with quotation marks.</p>
<p><input type="text" name="criteria" size="50" maxLength="50">
</p>
<p><input type="submit" value="Search"></p>
</form>
</body>
</html>
2 Save the file as collection_db_search_form.cfm in the myapps directory under the web_root.
This file is like collection_search_form.cfm, except the form uses collection_db_results.cfm, which you create in
the next step, as its action page.
3 Create another ColdFusion page with the following content:
501
<html>
<head>
<title>Search Results</title>
</head>
<body>
<cfsearch
collection="#Form.collname#"
name="getEmps"
criteria="#Form.Criteria#"
maxrows = "100">
<!--- Output the record set. --->
<cfoutput>
Your search returned #getEmps.RecordCount# file(s).
</cfoutput>
<cfoutput query="getEmps">
<p><table>
<tr><td>Title: </td><td>#Title#</td></tr>
<tr><td>Score: </td><td>#Score#</td></tr>
<tr><td>Key: </td><td>#Key#</td></tr>
<tr><td>Summary: </td><td>#Summary#</td></tr>
<tr><td>Custom 1:</td><td>#Custom1#</td></tr>
<tr><td>Column list: </td><td>#ColumnList#</td></tr>
</table></p>
</cfoutput>
</body>
</html>
4 Save the file as collection_db_results.cfm in the myapps directory under the web_root.
5 View collection_db_search_form.cfm in the web browser and enter the name of the collection and search terms.
502
503
The ColdFusion cfindex tag indexes the contents of the specified directory path.
Search and display the directory path
1 Create a ColdFusion page that contains the following content:
<cfsearch
collection="#Form.collname#"
name="getEmps"
criteria="#Form.Criteria#"
maxrows = "100">
<!--- Output the directory path contained in the record set. --->
<cfoutput>
Your search returned #getEmps.RecordCount# file(s).
</cfoutput>
<cfoutput query="getEmps">
<p><table>
<tr><td>Title: </td><td>#Title#</td></tr>
<tr><td>Score: </td><td>#Score#</td></tr>
<tr><td>Key: </td><td>#Key#</td></tr>
<tr><td>Summary: </td><td>#Summary#</td></tr>
<tr><td>Custom 1:</td><td>#Custom1#</td></tr>
<tr><td>Column list: </td><td>#ColumnList#</td></tr>
</table></p>
</cfoutput>
504
When creating an index from an LDAP query, remember the following considerations:
Because LDAP structures vary greatly, you must know the directory schema of the server and the exact name of
every LDAP attribute that you intend to use in a query.
505
As with the other query types, provide a unique value for the key attribute and enter the data fields to index in the body
attribute.
The following example updates the pop_query collection with the current mail for user1, and searches and returns the
message number and subject line for all messages that contain the word action:
<!--- Run POP query. --->
<cfpop action="getall"
name="p_messages"
server="mail.company.com"
userName="user1"
password="user1">
<!--- Output POP query record set. --->
<cfoutput query="p_messages">
#messagenumber# <br>
#from# <br>
#to# <br>
#subject# <br>
#body# <br>
<hr>
</cfoutput>
<!--- Index record set. --->
<cfindex action="refresh"
collection="pop_query"
key="messagenumber"
type="custom"
title="subject"
query="p_messages"
body="body">
<!--- Search messages for the word "action". --->
<cfsearch collection="pop_query"
name="s_messages"
criteria="action"
maxrows = "100">
<!--- Output search record set. --->
<cfoutput query="s_messages">
#key#, #title# <br>
</cfoutput>
506
Query type
Content
Simple
CFML example
<cfsearch name = "band_search"
collection="bbb"
type = "simple"
criteria="film">
Explicit
Words, operators,
modifiers
Must be specified
Natural
Internet
Words, operators,
modifiers
The query type determines whether the search words that you enter are stemmed, and whether the retrieved words
contribute to relevance-ranked scoring. Both of these conditions occur by default in simple queries. For more
information on the STEM operator and MANY modifier, see Stemming in simple queries on page 507.
Note: Operators and modifiers are formatted as uppercase letters here solely to enhance legibility. They might be all
lowercase or uppercase.
Search result
low,brass,instrument
film
filming OR fun
507
The operators AND and OR, and the modifier NOT, do not require angle brackets (<>). Operators typically require
angle brackets and are used in explicit queries. For more information about operators and modifiers, see Operators
and modifiers on page 515.
Preventing stemming
When entering text on a search form, you can prevent Verity from implicitly adding the STEM operator by doing one
of the following:
508
When you specify type="explicit" the search expression must be a valid Verity Query Language expression. As a
result, an individual search term must be in explicit quotation marks. The following table shows valid and invalid
criteria:
Attribute
Effect
criteria="government"
Generates an error
criteria="'government'" or
criteria='"government"'
criteria="<WORD>government"
criteria="<STEM>government"
criteria="<MANY><STEM>government"
criteria="<WILDCARD>governmen*"
To search for a literal AND, OR, or NOT, enclose the literal term in double-quotation marks; for example:
love "and" marriage
Note: Although NOT is a modifier, you use it only with the AND and OR operators. Therefore, it is sometimes casually
referred to as an operator.
For more information, see Operators and modifiers on page 515.
The following table gives examples of searches and their results:
Search term
509
Description
Example
Search result
apple?
apples or applet
[]
<WILDCARD> 'sl[iau]m'
{}
<WILDCARD> 'hoist{s,ing,ed}'
<WILDCARD>'sl[^ia]m'
<WILDCARD> 'c[a-r]t'
To search for a wildcard character as a literal, place a backslash character before it:
To match a question mark or other wildcard character, precede the ? with one backslash. For example, type the
following in a search form: Checkers\?
To match a literal asterisk, you precede the * with two backslashes, and enclose the search term with either single
or double quotation marks. For example, type the following in a search form: 'M\\*' (or "M\*") The following is the
corresponding CFML code:
<cfsearch name = "quick_search"
collection="bbb"
type = "simple"
criteria="'M\\*'">
Description
,()[
=><!
These characters also end a text token. They are terminated by an associated end character.
'`<{[!
These characters signify the start of a delimited token. They are terminated by an associated end character.
510
To search for special characters as literals, precede the following nonalphanumeric characters with a backslash
character (\) in a search string:
comma (,)
left parenthesis (
right parenthesis )
double-quotation mark (")
backslash (\)
left curly bracket ({)
left bracket ([)
less than sign (<)
backquote (`)
In addition to the backslash character, you can use paired backquote characters (` `) to interpret special characters as
literals. For example, to search for the wildcard string a{b you can surround the string with back quotation marks,
as follows:
`a{b`
To search for a wildcard string that includes the literal backquote character (`) use two backquote characters together
and surround the entire string in back quotation marks:
`*n``t`
You can use paired back quotation marks or backslashes to escape special characters. There is no functional difference
between the two. For example, you can query for the term: <DDA> using \<DDA\> or `<DDA>` as your search term.
511
Note: Verity also includes the Internet_BasicWeb and Internet_AdvancedWeb query parsers, which are not directly
supported by ColdFusion.
Search terms
In a search form enabled with the Internet query parser, users can enter words, phrases, and plain language. The
Internet parser does not support the Verity query language (VQL).
Words
To search for multiple words, separate them with spaces.
Phrases
To search for an exact phrase, surround it with double-quotation marks. A string of capitalized words is assumed to
be a name. Separate a series of names with commas. Commas arent needed when the phrases are surrounded by
quotation marks.
The following example searches for a document that contains the phrases San Francisco and sourdough bread:
"San Francisco" "sourdough bread"
Plain language
To search with plain language, enter a question or concept. The Internet Query Parser identifies the important words
and searches for them. For example, enter a question such as:
Where is the sales office in San Francisco?
Field searches
The Internet parser lets users perform field searches. The fields that are available for searching depend on field
extraction rules based on the document type of the documents in the collection.
512
To search a document field, type the name of the field, a colon (:), and the search term with no spaces.
field:term
If you enter a minus sign () immediately preceding field, documents that contain the specified term are excluded from
the search results. For example, if you enter -field:term, documents that contain the specified term in the specified
field are excluded from the results of the search.
If you enter a plus sign (+) immediately proceeding the field search specification, such as +field:term, documents
are included in the search results only if the search term is present in the specified field.
Field searches are enabled by the enableField parameter in a template file. This parameter, set to 0 by default, must
be set to 1 to allow searching a document field.
Important: The enableField parameter is the only thing in a template file to be modified.
Query syntax
The query syntax is like the syntax that users expect to use on the web. Queries are interpreted according to the
following rules:
Individual search terms are separated by whitespace characters, such as a space, tab, or comma, for example:
cake recipes
Exclude terms with the negation operator, minus ( - ), or the NOT operator, for example:
cake recipes -rum
cake recipes NOT rum
Require a compulsory term with the unary inclusion operator, plus sign (+); in this example, the term chocolate
must be included:
cake recipes +chocolate
Require compulsory terms with the binary inclusion operator AND; in this example, the terms recipes and chocolate
must be included:
cake recipes and chocolate
Field searches
You can search fields or zones by specifying name: term, where:
name is the name of the field or zone
term is an individual search term or phrase
For example:
bakery city:"San Francisco"
bakery city:Sunnyvale
For more information, see Refining your searches with zones and fields on page 522.
513
Pass-through of terms
Search terms are passed through to the VDK-level and are interpreted as Verity Query Language (VQL) syntax. No
issues arise if the terms contain only alphabetic or numeric characters. Other kinds of characters might be interpreted
by the language youre using. If a term contains a character that is not handled by the specified language, it can be
interpreted as VQL. For example, a search term that includes an asterisk (*)can be interpreted as a wildcard.
Stop words
The configurable Internet query parser uses its own stop-word list, qp_inet.stp, to specify terms to ignore for natural
language processing.
Note: You can override the stop out by using quotation marks around the word.
For example, the following stop words are provided in the query parsers stop-word file for the English (Basic)
template:
a
did
or
what
also
do
im
should
when
an
does
if
so
where
and
find
in
than
whether
any
for
is
that
which
am
from
it
the
who
are
get
its
there
whose
as
got
its
to
why
at
had
like
too
will
be
has
not
want
with
but
have
of
was
would
can
how
on
were
<or>
Verity provides a populated stop-word file for the English and English (Advanced) languages. You need not modify
the qp_inet.stp file for these languages. If you use the configurable Internet query parser for another language, provide
your own qp_inet.stp file that contains the stop words that you want to ignore in that language. This stop-word file
must contain, at a minimum, the language-equivalent words for or and <or>.
Note: The configurable Internet query parsers stop-word file contains a different word list than the vdk30.stp word file,
which is used for other purposes, such as summarization.
Case sensitivity
Verity searches are case sensitive only when the search term is entered in mixed case. For example, a search for zeus
finds zeus, Zeus, or ZEUS; however, a search for Zeus finds only Zeus.
To have your application always ignore the case that the user types, use the ColdFusion LCase function in the
criteria attribute of cfsearch. The following code converts user input to lowercase, thereby eliminating case
sensitivity concerns:
514
<cfsearch name="results"
collection="#form.collname#"
criteria="#LCase(form.criteria)#"
type="#form.type#">
Commas in expressions
If an expression includes two or more search terms within parentheses, a comma is required between the elements
(whitespace is ignored). The following example searches for documents that contain any combination of Larry and
Jerome together:
AND (Larry, Jerome)
Precedence rules
Expressions are read from left to right. The AND operator takes precedence over the OR operator; however, terms
enclosed in parentheses are evaluated first. When the search engine encounters nested parentheses, it starts with the
innermost term.
Example
Search result
(Same as above)
Delimiters in expressions
You use angle brackets (< >), double quotation marks ("), and backslashes (\) to delimit various elements in a search
expression, as the following table describes:
515
Character
Usage
<>
Left and right angle brackets are reserved for designating operators and modifiers. They are optional for the AND, OR,
and NOT, but required for all other operators.
"
Use double quotation marks in expressions to search for a word that is otherwise reserved as an operator or modifier,
such as AND, OR, and NOT.
To include a backslash in a search expression, insert two backslashes for each backslash character that you want
included in the search; for example, C:\\CFusion\\bin.
Purpose
Concept
Relational
Evidence
Proximity
Score
Manipulates the score returned by a search element. You can set the score percentage display to four decimal
places.
The following table shows the operators, according to type, that are available for conducting searches of ColdFusion
Verity collections:
Concept
Relational
Evidence
Proximity
Score
ACCRUE
<
STEM
NEAR
YESNO
ALL
<=
WILDCARD
NEAR/N
PRODUCT
AND
WORD
PARAGRAPH
SUM
ANY
>
THESAURUS
PHRASE
COMPLEMENT
OR
>=
SOUNDEX
SENTENCE
CONTAINS
TYPO/N
IN
MATCHES
516
STARTS
ENDS
SUBSTRING
Concept operators
Concept operators combine the meaning of search elements to identify a concept in a document. Documents retrieved
using concept operators are ranked by relevance. The following table describes each concept operator:
Operator
Description
AND
Selects documents that contain all the search elements that you specify.
OR
Selects documents that show evidence of at least one of the search elements that you specify.
ACCRUE
Selects documents that include at least one of the search elements that you specify. Documents are ranked based
on the number of search elements found.
ALL
Selects documents that contain all of the search elements that you specify. A score of 1.00 is assigned to each
retrieved document. ALL and AND retrieve the same results, but queries using ALL are always assigned a score of
1.00.
ANY
Selects documents that contain at least one of the search elements that you specify. A score of 1.00 is assigned to
each retrieved document. ANY and OR retrieve the same results, but queries using ANY are always assigned a score
of 1.00.
Relational operators
Relational operators search document fields (such as AUTHOR) that you defined in the collection. Documents that
contain specified field values are returned. Documents retrieved using relational operators are not ranked by
relevance, and you cannot use the MANY modifier with relational operators.
You use the following operators for numeric and date comparisons:
Operator
Description
Equal
!=
Not equal
>
Greater than
>=
<
Less than
<=
For example, to search for documents that contain values for 1999 through 2002, you perform either of the following
searches:
517
Operator
Description
Example
CONTAINS
MATCHES
Selects documents by matching the query string with values stored in For examples, see the text immediately following
a specific document field. Documents are selected only if the search this table.
elements specified match the field value exactly. If a partial match is
found, a document is not selected. When you use the MATCHES
operator, you specify the field name to search, and the word, phrase,
or number to locate. You can use ? and * to represent individual and
multiple characters, respectively, within a string.
STARTS
Selects documents by matching the character string that you specify In a document field named REPORTER, to retrieve
with the starting characters of the values stored in a specific
documents written by Clark, Clarks, and Clarkson,
document field.
search for REPORTER <STARTS> Clark.
ENDS
Selects documents by matching the character string that you specify In a document field named OFFICER, to retrieve
with the ending characters of the values stored in a specific
arrest reports written by Tanner, Garner, and Milner,
document field.
search for OFFICER <ENDS> ner.
SUBSTRING
For example, assume a document field named SOURCE includes the following values:
Computer
Computerworld
Computer Currents
PC Computing
To locate documents whose source is Computer, enter the following:
SOURCE <MATCHES> computer
To locate documents whose source is Computer, Computerworld, and Computer Currents, enter the following:
SOURCE <MATCHES> computer*
To locate documents whose source is Computer, Computerworld, Computer Currents, and PC Computing, enter the
following:
SOURCE <MATCHES> *comput*
For an example of ColdFusion code that uses the CONTAINS relational operator, see Field searches on page 523.
You can use the SUBSTRING operator to match a character string with data stored in a specified data source. In the
example described here, a data source called TEST1 contains the table YearPlaceText, which contains three columns:
Year, Place, and Text. Year and Place make up the primary key. The following table shows the TEST1 schema:
518
Year
Place
Text
1990
Utah
1990
Oregon
1991
Utah
1991
Oregon
1992
Utah
The following application page matches records that have 1990 in the TEXT column and are in the Place Utah. The
search operates on the collection that contains the TEXT column and then narrows further by searching for the string
Utah in the CF_TITLE document field. Document fields are defaults defined in every collection corresponding to the
values that you define for URL, TITLE, and KEY in the cfindex tag.
<cfquery name="GetText"
datasource="TEST1">
SELECT Year || Place AS Identifier, text
FROM YearPlaceText
</cfquery>
<cfindex collection="testcollection"
action="Update"
type="Custom"
title="Identifier"
key="Identifier"
body="TEXT"
query="GetText">
<cfsearch name="GetText_Search"
collection="testcollection"
type="Explicit"
criteria="1990 and CF_TITLE <SUBSTRING> Utah">
<cfoutput>
Record Counts: <br>
#GetText.RecordCount# <br>
#GetText_Search.RecordCount# <br>
</cfoutput>
Query Results --- Should be 5 rows <br>
<cfoutput query="Gettext">
#Identifier# <br>
</cfoutput>
Search Results -- should be 1 row <br>
<cfoutput query="GetText_Search">
#GetText_Search.TITLE# <br>
</cfoutput>
Evidence operators
Evidence operators let you specify a basic word search or an intelligent word search. A basic word search finds
documents that contain only the word or words specified in the query. An intelligent word search expands the query
terms to create an expanded word list so that the search returns documents that contain variations of the query terms.
Documents retrieved using evidence operators are not ranked by relevance unless you use the MANY modifier.
519
Description
Example
STEM
Expands the search to include the word that you enter and its
variations. The STEM operator is automatically implied in any
simple query.
WILDCARD
WORD
THESAURUS
Expands the search to include the word that you enter and its
synonyms. Collections do not have a thesaurus by default; to use
this feature you must build one.
SOUNDEX
Expands the search to include the word that you enter and one or <SOUNDEX> sale retrieves words such as sale, sell,
more words that sound like, or whose letter pattern is similar to, seal, shell, soul, and scale.
the word specified. Collections do not have sound-alike indexes by
default; to use this feature you must build sound-alike indexes.
TYPO/N
Expands the search to include the word that you enter plus words <TYPO> swept retrieves kept.
that are similar to the query term. This operator performs
approximate pattern matching to identify similar words. The
optional N variable in the operator name expresses the maximum
number of errors between the query term and a matched term, a
value called the error distance. If N is not specified, the default error
distance is 2.
Proximity operators
Proximity operators specify the relative location of specific words in the document. To retrieve a document, the
specified words must be in the same phrase, paragraph, or sentence. In the case of NEAR and NEAR/N operators,
retrieved documents are ranked by relevance based on the proximity of the specified words. Proximity operators can
be nested; phrases or words can appear within SENTENCE or PARAGRAPH operators, and SENTENCE operators
can appear within PARAGRAPH operators.
The following table describes the proximity operators:
520
Operator
Description
Example
NEAR
NEAR/N
Selects documents that include all of the words you specify within <PARAGRAPH> (mission, goal, statement) retrieves
the same paragraph. To search for three or more words or phrases in documents that contain these terms within a
a paragraph, you must use the PARAGRAPH operator between each paragraph.
word or phrase.
PHRASE
SENTENCE
Selects documents that include all of the words you specify within
the same sentence.
IN
For an example using the IN proximity operator to search XML documents, see Zone searches on page 522.
Score operators
Score operators control how the search engine calculates scores for retrieved documents. The maximum score that a
returned search element can have is 1.000. You can set the score to display a maximum of four decimal places.
When you use a score operator, the search engine first calculates a separate score for each search element found in a
document, and then performs a mathematical operation on the individual element scores to arrive at the final score
for each document.
The documents score is available as a result column. You can use the SCORE result column to get the relevancy score
of any document retrieved, for example:
<cfoutput>
<a href="#Search1.URL#">#Search1.Title#</a><br>
Document Score=#Search1.SCORE#<BR>
</cfoutput>
521
Operator
Description
Example
YESNO
PRODUCT
SUM
Adds the scores for the search element in each document matching a <SUM>(computers, laptops) takes the sum of
query, up to a maximum value of 1.
the resulting scores.
COMPLEMENT
Modifiers
You combine modifiers with operators to change the standard behavior of an operator in some way. The following
table describes the available modifiers:
Modifier
Description
Example
CASE
Specifies a case-sensitive search. Normally, Verity searches are case<CASE>Java OR <CASE>java retrieves
insensitive for search text entered in all uppercase or all lowercase, and documents that contain Java or java, but not
case-sensitive for mixed-case search strings.
JAVA.
MANY
<PARAGRAPH><MANY>javascript <AND>
vbscript.
WORD
WILDCARD
AND
STEM
OR
PHRASE
ACCRUE
SENTENCE
Relational operators
PARAGRAPH
NOT
ORDER
Specifies that the search elements must occur in the same order in
<ORDER><PARAGRAPH> ("server", "Java")
which you specify them in the query. Use with the following operators: retrieves documents that contain server
before Java.
PARAGRAPH
SENTENCE
NEAR/N
522
Zone searches
You can perform zone searches on markup language documents. The Verity zone filter includes built-in support for
HTML and several file formats; for a list of supported file formats, see Building a Search Interface on page 476. Verity
searches XML files by treating the XML tags as zones. When you use the zone filter, the Verity engine builds zone
information into the collections full-word index. This index, enhanced with zone information, permits quick and
efficient searches over zones. The zone filter can automatically define a zone, or you can define it yourself in the
style.zon file. You can use zone searching to limit your search to a particular zone. This can produce more accurate,
but not necessarily faster, search results than searching an entire file.
Note: The contents of a zone cannot be returned in the results list of an application.
Examples
The following examples perform zone searching on XML files. In a list of rock bands, you could have XML files with
tags for the instruments and for comments. In the following XML file, the word Pete appears in a comment field:
<band.xml>
<Lead_Guitar>Dan</Lead_Guitar>
<Rhythm_Guitar>Jake</Rhythm_Guitar>
<Bass_Guitar>Mike</Bass_Guitar>
<Drums>Chris</Drums>
<COMMENT_A>Dan plays guitar, better than Pete.</COMMENT_A>
<COMMENT_B>Jake plays rhythm guitar.</COMMENT_B>
</band.xml>
The following CFML code shows a search for the word Pete:
<cfsearch name = "band_search"
collection="my_collection"
type = "simple"
criteria="Pete">
The above search for Pete returns this XML file because this search target is in the COMMENT_A field. In contrast,
Pete is the lead guitarist in the following XML file:
523
<band.xml>
<Lead_Guitar>Pete</Lead_Guitar>
<Rhythm_Guitar>Roger</Rhythm_Guitar>
<Bass_Guitar>John</Bass_Guitar>
<Drums>Kenny</Drums>
<COMMENT_A>Who knows who's better than this band?</COMMENT_A>
<COMMENT_B>Ticket prices correlated with decibels.</COMMENT_B>
</band.xml>
To retrieve only the files in which Pete is the lead guitarist, perform a zone search using the IN operator according to
the following syntax:
(query) <IN> (zone1, zone2, ...)
Note: As with other operators, IN might be uppercase or lowercase. Unlike AND, OR, or NOT, enclose IN within brackets.
Thus, the following explicit search retrieves files in which Pete is the lead guitarist:
(Pete) <in> Lead_Guitar
To retrieve files in which Pete plays either lead or rhythm guitar, use the following explicit search:
(Pete) <in> (Lead_Guitar,Rhythm_Guitar)
Field searches
Fields are extracted from the document and stored in the collection for retrieval and searching, and can be returned
on a results list. Zones, on the other hand, are merely the definitions of regions of a document for searching purposes,
and are not physically extracted from the document in the same way that fields are extracted.
You must define a region of text as a zone before it can be a field. Therefore, it can be only a zone, or it can be both a
field and a zone. Whether you define a region of text as a zone only or as both a field and a zone depends on your
particular requirements.
A field must be defined in the style file, style.ufl, before you create the collection. To map zones to fields (to display
field data), define and add these extra fields to style.ufl.
You can specify the values for the cfindex attributes TITLE, KEY, and URL as document fields for use with relational
operators in the criteria attribute. (The SCORE and SUMMARY attributes are automatically returned by a
cfsearch; these attributes are different for each record of a collection as the search criteria changes.) Text comparison
operators can reference the following document fields:
cf_title
cf_key
cf_url
524
cf_custom1
cf_custom2
cf_custom3
cf_custom4
Text comparison operators can also reference the following automatically populated document fields:
title
key
url
vdksummary
author
mime-type
To explore how to use document fields to refine a search, consider the following database table, named Calls. This table
has four columns and three records, as the following table shows:
call_ID
Problem_Description
Short_Description
Product
Bold Problem
HomeSite+
Attributes Problem
ColdFusion
HomeSite+
A Verity search for the word certain returns three records. However, you can use the document fields to restrict your
search; for example, a search to retrieve HomeSite+ problems with the word certain in the problem description.
These are the requirements to run this procedure:
The cfindex
attribute
Comment
call_ID
key
Problem_Description
body
Short_Description
title
Product
custom1
The following code shows the cfindex tag for indexing the collection (the type attribute is set to custom for tabular
data):
525
<cfindex
query = "Calls"
collection = "training"
action = "UPDATE"
type = "CUSTOM"
title = "Short_Description"
key = "Call_ID"
body = "Problem_Description"
custom1 = "Product">
To perform the refined search for HomeSite+ problems with the word certain in the problem description, the
cfsearch tag uses the CONTAINS operator in its criteria attribute:
<cfsearch
collection = "training"
name = "search_calls"
criteria = "certain and CF_CUSTOM1 <CONTAINS> HomeSite">
XML/HTTP Interfaces
Loose schema to define types and fields
Web Administration Interface
Extensive Caching
Index Replication
Extensible Open Architecture
Written in Java5, deployable as a WAR
Support for stemming
Last updated 1/20/2012
526
a Solr collection, you do not need to specify the language. Language can be specified in the <cfindex> tag. All other
attributes remain the same.
cfindex ColdFusion detects the search engine based on the collection name.
Language support
Solr supports the following languages:
Danish
Dutch
Finnish
French
German
Italian
Norwegian
Spanish
Portugese
Russian
Swedish
Chinese
Japanese
Korean
Czech
Greek
Thai
Solr supports documents in any language. If the document has a language (for example, Arabic) not listed above, it can
still index the content, but stemming is not available. In this case, do not specify a language attribute in the cfindex tag.
Solr supports stemming. That is, it considers the root form (stem) of the word for search. This applies only if you
provide the attribute language.
Single word search: The following example shows how to search for a single word in a collection:
<cfsearch name="qsearch1" collection="solr_complex" criteria="Graphics">
527
Multiple word search: The following example shows how to search a document or query having words
"ColdFusion" and "Green" in it:
<cfsearch name="qsearch1"
collection="solr_complex"
criteria="+Green +Coldfusion">
Search with at least one word: The following example shows how search for at least "Coldfusion" OR (Green OR
Blue):
<cfsearch name="qsearch1"
collection="solr_complex"
criteria=" +Coldfusion Green Blue">
Search for one word, but not the other: The following example shows how to search for "Green" but NOT
"Coldfusion":
<cfsearch name="qsearch1"
collection="solr_complex"
criteria=" -Coldfusion +Green">
Fuzzy search: The following example shows how to search words like roam, roams, foam, foams:
<cfsearch name="qsearch1"
collection="solr_complex"
criteria=" roam~">
Wildcard search: The following syntax searches for 'test', 'text', 'teat', and so on:
<cfsearch name="qsearch1"
collection="solr_complex"
criteria=" te?t">
Note: You cannot use a * or question mark (?) symbol as the first character of a search.
Proximity search: To search for "apache" and "jakarta" within five words of each other in a document, use the
following search:
<cfsearch name="qsearch1"
collection="solr_complex"
criteria='"jakarta apache" ~10'>
Range Search: Following searches all documents with title between 'fuzzy1.txt' to 'text1.txt':
<cfsearch name="qsearch"
collection="solr_srch"
criteria="title:fuzzy1.txt TO text1.txt">
528
These ranges are inclusive of start and end terms. To exclude them, use curly brackets{} instead.
String search:
<cfsearch name="qsearch1"
collection="solr_complex"
criteria='"Cold Fusiongava" OR "Internet Tools"'>
Searching synonyms: There are two ways to search documents that have synonymous words like 'MB', 'megabyte',
'gig', and so on:
1 If collection is not yet created, go to:
<cf_home>/solr/multicore/template/conf/synonyms.txt
This file contains some default mappings such as 'GB, gig, gigabyte, gigabytes'. Define your synonym
mappings in the next row.
2 If you want to add a synonym mapping for a collection that is already created, go to
<collection_location>/conf/synonyms.txt and define your mapping.
Term highlighting
By default, Solr highlights searched terms in the summary content as described in the following snippet:
529
<cfsearch
collection="syn1"
criteria="Services solr"
name="results"
status="r"
suggestions="always"
contextPassages="1">
To highlight contents in the entire document, modify the solrconfig.xml and schema.xml files. These files are available
in the following locations:
<Collection Directory>/conf: Modify files in this location to apply the changes to all future Solr collections.
<Solr Home>/multicore/template/conf: Modify files in this location to apply the changes only to a particular
collection.
1 Stop Solr service.
2 Replace the following section in the solrconfig.xml
<requestHandler name="standard" class="solr.StandardRequestHandler" default="true">
<!-- default values for query parameters -->
<lst name="defaults">
<str name="echoParams">explicit</str>
<str name="hl.fl">summary title </str>
<!-- omp = Only More Popular -->
<str name="spellcheck.onlyMorePopular">false</str>
<!-- exr = Extended Results -->
<str name="spellcheck.extendedResults">false</str>
<!-- The number of suggestions to return -->
<str name="spellcheck.count">1</str>
</lst>
<arr name="last-components">
<str>spellcheck</str>
</arr>
</requestHandler>
with
<requestHandler name="standard" class="solr.StandardRequestHandler" default="true">
<!-- default values for query parameters -->
<lst name="defaults">
<str name="echoParams">explicit</str>
<str name="hl.fl">contents title </str>
<!-- omp = Only More Popular -->
<str name="spellcheck.onlyMorePopular">false</str>
<!-- exr = Extended Results -->
<str name="spellcheck.extendedResults">false</str>
<!-- The number of suggestions to return -->
<str name="spellcheck.count">1</str>
</lst>
<arr name="last-components">
<str>spellcheck</str>
</arr>
</requestHandler>
530
stored="false" required="false"
with
<field name="contents" type="text" indexed="true" stored="true" required="false"
multiValued="true" omitNorms="true"/>
4 Restart Solr.
5 Reindex the collection.
Note: The modifications to solrconfig.xml and schema.xml will increase the index size.
However, in Verity the criteria for searching the same term is:
<cfsearch
name="qsearch1"
collection="Verity_complex"
type="simple"
criteria="Green AND Coldfusion">
Using wildcards:
Solr
531
<cfsearch
name="qsearch1"
collection="solr_complex"
criteria ="te?t">
Verity
<cfsearch
name="qsearch1"
collection="Verity_complex"
type="explicit"
criteria="<WILDCARD>te?t">
Searching titles
Solr:
<cfsearch
name="qsearch1"
collection="solr_complex"
criteria ="title:fuzzy?.txt">
Verity:
<cfsearch
name="qsearch1"
collection="Verity_complex"
type="explicit"criteria="CF_TITLE<SUBSTRING>fuzzy">
For more examples of how search criteria is set in Solr, see Solr search examples on page 526 and for Verity, see
Using Verity Search Expressions on page 505.
2 In the cfsolr script, modify the line that starts with VMARGS= by changing the default value -Xmx256m with an
Windows platform
1 Stop the Solr service ColdFusion 9 Solr Service.
2 In the solr.lax, modify the line that starts with lax.nl.java.option.additional= by changing the default value
532
Note: Enabling term highlighting increases the size of the Solr collection. So ensure that you allocate adequate memory
for Solr if you are enabling term highlighting.
Upgrading Solr
Solr is upgraded as part of updater.
Therefore, to use Solr with ColdFusion 9.0.1, upgrade Solr.
For local installation, Solr is auto-upgraded when you run the ColdFusion Updater.
For remote installation, manually upgrade Solr using the following steps:
1 Stop Solr.
2 Back up solr.xml available in Solr_Home/multicore.
3 Uninstall Solr.
4 Reinstall the standalone version of Solr available on Adobe download location.
5 Stop Solr (if it has started automatically).
6 Bring back the backed up copy of solr.xml to Solr_Home/multicore.
Note: After you upgrade, ensure that you reindex the entire Solr collection before you use the search service.
533
Managing relational data using tags such as cfquery, cfinsert, and cfupdate, which handle SQL statements.
Managing objects using ColdFusion components (CFCs), and object lifecycle using the application itself
Writing SQL queries for each CFC, even for basic CRUD (Create, Retrieve, Update, and Delete) operations.
The complexity of managing these tasks increases as your application grows.
ColdFusion ORM automates most of these tasks, which:
534
The following example explains these concepts by building a simple application, which would enable you to jumpstart
with ColdFusion ORM. The example uses the cfartgallery data source that is shipped as part of ColdFusion 9
documentation option in the installer. The cfartgallery data source has Artists and Art tables. Artists has a one-tomany relationship with the Art table.
Step 1:
Specify the ORM settings in the Application.cfc file.
The minimum required settings are mentioned in the following sample code snippet:
Application.cfc
<cfset this.name = "ArtGalleryApp">
<cfset this.ormenabled = "true">
<cfset this.datasource = "cfartgallery">
Apart from these, there are other settings that you can use to configure ORM. For details, see ORM settings on
page 538.
Important: Define these setting only in Application.cfc and not in Application.cfm.
Step 2:
Map the ARTISTS.cfc to the database table.
1 Create the ARTISTS.cfc.
2 Flag it as a persistent CFC and map it to the ARTISTS table.
To make the ARTISTS.cfc persistent, the persistent attribute should be set to true in the cfcomponent tag. The
table attribute should be set to the table name. If table attribute is not specified, then the CFC name is taken as the
table name.
Each CFC can be given an entity name. Entity name is the name used by the ORM related functions to work with
the persistent CFC. It can be specified by using the entityname attribute in cfcomponent. If entityname is not
specified, then the CFC name is taken as the entityname.
3 Now, create properties in ARTISTS.cfc and map them to the columns in the table. One property should be created
for each column in the table. To map the property to the column, the column attribute should be set to the
corresponding column name. If the column attribute is not specified, then the name of the property is taken as the
column name.
For details on setting the ORM-specific attributes, see Define ORM mapping on page 542.
The ARTISTS.cfc is defined as follows:
<cfcomponent persistent="true">
<cfproperty name="id" column = "ARTISTID" generator="increment">
<cfproperty name="FIRSTNAME">
<cfproperty name="LASTNAME">
<cfproperty name="ADDRESS">
<cfproperty name="CITY">
<cfproperty name="STATE">
<cfproperty name="POSTALCODE">
<cfproperty name="EMAIL">
<cfproperty name="PHONE">
<cfproperty name="FAX">
<cfproperty name="thepassword">
</cfcomponent>
535
Step 3:
Perform CRUD operations.
To retrieve data from the ARTISTS table, use EntityLoad():
ARTISTS = EntityLoad("ARTISTS")
All the records from the ARTISTS table are retrieved as an object array.
To add a new artist, create a new artist object and call EntitySave() for this object.
<cfscript>
try {
newArtistObj = EntityNew("artists");
newArtistObj.setfirstname("John");
newArtistObj.setlastname("Smith");
newArtistObj.setaddress("5 Newport lane");
newArtistObj.setcity("San Francisco");
newArtistObj.setstate("CA");
newArtistObj.setPostalCode("90012");
newArtistObj.setphone("612-832-2343");
newArtistObj.setfax("612-832-2344");
newArtistObj.setemail("[email protected]");
newArtistObj.setThePassword("jsmith");
EntitySave(newartistobj);
ormflush();
} catch(Exception ex) {
WriteOutput("<p>#ex.message#</p>");
}
</cfscript>
To update an existing record, load that object and make changes to it. ColdFusion automatically detects that the row
for this object needs to be updated and it will get updated when ORMFlush() is called.
Note: ORMFlush() is called at the end of the request by default.
In the following code, the newArtistObj is already managed by ORM, so it does not need to be loaded again.
newArtistObj.setphone("612-832-1111");
ormflush();
Step 4:
Define Relationships
First define the mapping for the ART table to define a relationship between artwork and artists.
The ART.cfc is defined as follows:
536
<cfcomponent persistent="true">
<cfproperty name="artid" generator="increment">
<cfproperty name="artname">
<cfproperty name="price">
<cfproperty name="largeimage">
<cfproperty name="mediaid">
<cfproperty name="issold">
</cfcomponent>
In cfartgallery, the table ARTISTS has a one-to-many relationship with ART table, which are joined using the foreign
key column ARTISTID. This means that each artist has created multiple artwork pieces and many artworks are created
by one artist. To represent this in the object model, each ARTISTS object would contain an array of ART objects. Each
ART object will contain a reference to its ARTISTS object. This is an example of a bidirectional relationship.
To achieve this, you need to add an extra property to the ARTISTS.cfc object that contains the array of ART objects
for that ARTIST.
<cfproperty name="art" type="array" fieldtype="one-to-many" cfc="Art" fkcolumn="ARTISTID">
fieldtype="one-to-many" specifies the type of relation.
CFC="Art" is used to convey that the relationship is with "ART" cfc.
fkcolumn="artistid" specifies the foreign key.
ART forms a many-to-one relationship with ARTISTS table because each piece of artwork is created by an artist and
many other pieces of artwork are created by the same artist. To define this relationship, add a property in ART.cfc to
define the relationship with ARTISTS.cfc.
<cfproperty name="artists" fieldtype="many-to-one" fkcolumn="artistid" cfc="Artists"
lazy="true">
fieldtype="many-to-one" specifies the type of relation.
CFC="ARTISTS" is used to convey that the relationship is with "ARTISTS" cfc.
fkcolumn="ARTISTID" specifies the foreign key.
Step 5:
Retrieve records in relationship
<cfscript>
artist = EntityLoad("Artists", 1, true);
arts = artist.getArts();
WriteOutput("<b>" & artist.getid() & " " & artist.getfirstname() & " " &
artist.getlastname() & "</b> has " & ArrayLen(arts) & " arts:<br>");
if (ArrayLen(arts) > 0)
{
for(j = 1; j <= ArrayLen(arts); j ++)
{
art = arts[j];
WriteOutput(art.getartname() & "<br>");
}
}
</cfscript>
537
Architecture
In ColdFusion ORM, you need to define an object mapping to create persistent objects. The object mapping includes
details such as:
538
For transactions, a new session is always created at the start of a transaction and ends at the end of a transaction. Any
previous open sessions are flushed and closed at the start of the transaction.
The Hibernate configuration is created and loaded only when the application starts. Therefore, any modifications to
the mapping in the persistent CFCs or in the Hibernate mapping files are not loaded automatically. To load these
modifications, you can either restart the application or call ORMReload().
To restart the application, you can stop the application using ApplicationStop() and the next request to any page
in this application automatically starts it.
Configure ORM
The configuration for ORM is done in Application.cfc which makes this configuration application specific. For a
ColdFusion application to use ORM, the following are the mandatory settings that need to be configured:
1 Enable ORM for the application. To do this, set the ormenabled property to true in the THIS scope of
application.cfc
2 Provide the data source name by either setting data source property to true in the THIS scope of application or by
Description
ormenabled
Specifies whether ORM should be used for the ColdFusion application.Set the value to true to
use ORM. The default is false.
datasource
ormsettings
The struct that defines all the ORM settings. For details, see ORM settings on page 538
ORM settings
The following settings can be set in the ormsettings struct that ColdFusion uses to configure ORM. All these settings
are optional. If you specify the value of any ORM setting to true or yes, then the setting is enabled, otherwise it is
disabled.
539
Property Name
Default
Description
autogenmap
true
automanageSession
true
ColdFusion closes the ORM session at the end of request irrespective of this flag
being enabled or disabled.
Specifies the location of the configuration file that should be used by the
secondary cache provider.This setting is used only when
secondarycacheenabled=true.
cacheconfig
ehcache
Specifies the cache provider that should be used by ORM as secondary cache.
The values can be:
Ehcache
JBossCache
Hashtable
SwarmCache
OSCache
Fully qualified name of the class for any other cache provider.
This setting is used only when secondarycacheenabled=true.
See Secondary level cache on page 590 for details.
catalog
cfclocation
datasource
Specifies the data source that should be used by ORM. If it is not specified here,
then the data source specified for the application is picked up. Use the
following convention to specify a datasource name:
this.datasource="<datasource_name>";
dbcreate
none
ColdFusion ORM can automatically create the tables for your application in the
database when ORM is initialized for the application. This can be enabled by
using dbcreate in ormsettings. dbCreate takes the following values:
update: Setting this value creates the table if it does not exist or update the
table if it exists.
dropcreate: Setting this value drops the table if it exists and then creates it.
none (default): Setting this value does not change anything in the database
schema.
540
Property Name
Default
Description
Specifies the dialect.
dialect
DB2
DB2AS400
DB2OS390
Derby
PostgreSQL
MySQL
MySQLwithInnoDB
MySQLwithMyISAM
Oracle8i
Oracle9i
Oracle10g
Sybase
SybaseAnywhere
MicrosoftSQLServer
Informix
Apart from these dialects, you can specify custom dialects by using the fully
qualified class name.
false
Specifies whether ORM Event callbacks should be given. See Event Handling in
CFC for details.
flushatrequestend
true
logSQL
false
Specifies whether the SQL queries that are executed by ORM will be logged. If
LogSQL=true, the SQL queries are logged to the console.
namingstrategy
ormconfig
541
Property Name
Default
Description
savemapping
false
schema
secondarycacheenabled
false
skipCFCWithError
false
Lets you specify if ColdFusion must skip the CFCs that have errors. If set to
true, ColdFusion ignores the CFCs that have errors.
Path to the SQL script file that gets executed after ORM is initialized. This
applies if dbcreate is set to dropcreate. This must be the absolute file path
or the path relative to the application.The SQL script file lets you populate the
tables before the application is accessed.
sqlscript
useDBForMapping
true
Sample Application.cfc
<cfset this.name = "ArtGallery">
<cfset this.ormenabled = "true">
<cfset this.ormsettings={datasource="cfartgallery", logsql="true"}>
Logging
Monitoring SQL queries that get generated and executed by ORM is critical for troubleshooting and performance
optimization.
You can monitor and log the queries by:
Defining logsql in ormsettings: This is a simple way to quickly enable SQL logging. The flag should be enabled
in application.cfc:
<cfset this.ormsettings.logsql = "true">
This logs all the SQL queries that are generated by Hibernate to the console and servers output log file.
Using log4J.properties: Hibernate uses log4j for its logging and you can completely control its logging
including SQL by modifying the log4j.properties, which is present under <CF_HOME>/lib directory.
Following is a sample snippet from the log4j.properties file:
542
These settings control the SQLs that are generated for entity operations, how the data is bound to the statement
while executing, what SQLs are generated for DDL, and what operations are performed on the secondary cache. All
the logs get logged to console using HIBERNATECONSOLE which is actually a console appender. It can easily be
changed to a FileAppender, which will then be logged to a log file. The configuration controls the logging for the
following:
Description
log4j.logger.org.hibernate.SQL
This controls when and how the SQL will be logged. DEBUG says all the SQL will
be logged
log4j.logger.org.hibernate.type
log4j.logger.org.hibernate.tool.hbm2ddl
log4j.logger.org.hibernate.cache
543
Attributes
Attribute
Req/Opt
accessors
true
batchsize
Optional
Default
Description
If set to false, ColdFusion ORM does not generate the
implicit getters and setters.
cachename
optional
544
Attribute
Req/Opt
Default
Description
cacheuse
optional
none
catalog
Optional
discriminatorcolumn
optional
discriminatorvalue
optional
dynamicInsert
Optional
false
true
false
Optional
false
true
false
Optional
joincolumn
optional
lazy
Optional
true
true
false
Optional
version
none
version
dirty
all
545
Attribute
Req/Opt
Default
Description
persistent
Required
false
readonly
Optional
false
true
false
true
false
Optional
schema
Optional
selectbeforeupdate
Optional
false
true
false
Optional
546
Attribute
Req/Optional
default
optional
fieldtype
optional
Default
Description
This sets the default value on the property when the object is
created.
column
This attribute is used to specify the type of the property. Use this
attribute to specify the following:
name
required
type
optional
persistent
optional
true
optional
true
Primary key
Simple primary key
In a relational database, a primary key is defined as a key that uniquely identifies a row in a table. Typically, a table has
one primary key that represents a single column of information in the table.
To indicate that a cfproperty maps to a primary key in the table, set the attribute fieldtype="id".
547
Syntax
<cfproperty
name="property_name"
fieldType="id"
ormtype="type"
column="column_name"
generator="increment|identity
|sequence|sequence-identity|seqhilo
|uuid|guid|native|[assigned]|select|foreign"
params="{key1=val1,key2=val2...}"
sqltype="sql_type"
length="column_length"
unsavedvalue="instantiated_instance">
Example
An example to define an assigned primary key:
<cfproperty name="artistid" fieldtype="id" column="ARTISTID" generator="assigned">
An example to define a auto-generated primary key using a generator, which requires additional parameters:
<cfproperty name="id" fieldtype="id" column="ID" generator="sequence"
params="{sequence='id_sequence'}>
Attributes
Attribute
Req/Opt
Default
Description
column
Optional
fieldType
Optional
generator
Optional
length
optional
name
Required
ormtype
Optional
String
params
548
Attribute
Req/Opt
Default
Description
selectkey
optional
sqltype
optional
unSavedValue
optional
Composite Key
If the primary key consists of more than one column, it is called as a composite key. A composite key can be specified
by using fieldtype='id' on all the properties that form the primary key.
Example
If in a table, the columns Order_id and Product_id form a composite key, then, they should be defined as:
<cfproperty name="Order_Id" fieldtype="id" column="Order_Id">
<cfproperty name="Product_Id" fieldtype="id" column="Product_Id">
Generators
Generators are algorithms that are used to generate unique identifiers for instances of the persistent CFC. Generators
can have any one of the following values:
increment: This algorithm generates identifiers of type long, short, or int by incrementing a counter maintained
by ORM. This is commonly used when auto-generation for the primary key is not enabled in the table and you want
ORM to generate the primary key. This should be used when a single instance of ColdFusion is the only process to
insert data into the table.
identity: For databases such as DB2, MySQL, Sybase, and MS SQL, which support identity columns, you can use
identity key generation. The key is automatically generated by the database and the object is populated with the
generated key. This strategy requires ORM to execute two SQL queries to insert a new object.
sequence: For databases such as DB2, Oracle, PostgreSQL, Interbase, McKoi, and SAP, which support sequences,
you can use sequence style key generation. The key is automatically generated by the database and the object is
populated with the generated key. This strategy requires ORM to execute two SQL queries to insert a new object.
This generator includes the sequence parameter, which needs to be specified in the params attribute.
For example:
<cfproperty name="id" fieldtype="id" generator="sequence"
params="{sequence='id_sequence'}">
native: This algorithm is commonly used to automatically generate primary keys. This generator picks identity or
sequence depending upon the capabilities of the underlying database.
assigned: This algorithm is used when the application needs to assign its own identifier to the object. It is the
549
foreign: This is used with a <one-to-one> primary key association. In this case, the primary key is the same as
the primary key of the associated object. This generator would need the property parameter, which needs to be
specified in the params attribute. The value of the param property should be the name of the relationship property.
See One-to-one relationships for details.
Column
To indicate that a cfproperty maps to a column in the table, specify fieldtype="column". If the fieldtype is not
specified for cfproperty, it is mapped as a column property.
Syntax
<cfproperty
name="Property name"
fieldtype="column"
column="column_name"
persistent="true|false"
formula="SQL expression"
ormtype="ormtype"
update="[true]|false"
insert="[true]|false"
optimisticLock="[true]|false"
generated="true|[false]"
length="column_length"
precision="precision"
scale="scale"
index="index_name"
unique = "true|[false]"
uniquekey="uniquekey_name"
notnull="true|[false]"
dbdefault="default_col_value"
sqltype="sql_type">
Example
To specify a simple property:
<cfproperty name="FIRSTNAME"/>
To specify a property which has a different name than that of the column name:
<cfproperty name="LNAME" column="LASTNAME"/>
550
Attributes
Attribute
Req/Opt
Default
Description
column
optional
dbdefault
fieldType
optional
formula
optional
column
generated
optional
never
generated by database
generated by database
optional
true
name
Required
optimisticlock
optional
ormtype
optional
string
update
optional
true
DDL-only attributes
The following attributes are used only when DDL generation is required and not used for runtime.
551
Attribute
Req/Opt
Default
dbdefault
optional
index
optional
length
optional
notnull
optional
precision
optional
scale
optional
sqltype
optional
false
Description
For example:
<cfProperty name="active" ormtype="char"
sqltype="bit">
<cfProperty name="balance" ormtype="float"
sqltype="decimal(13,3)">
unique
optional
uniquekey
optional
Computed property
Computed property is a property whose value does not come from a column but is computed using a SQL query. Use
formula attribute to specify the SQL to be used to retrieve the value for this property.
<cfcomponent persistent="true" table="ARTISTS" schema="APP">
<cfproperty name="ID" column="ARTISTID" fieldtype="id"/>
<cfproperty name="FIRSTNAME"/>
<cfproperty name="LASTNAME"/>
<cfproperty name="NumberOfArts" formula="select count(*) from Art art where
art.ArtistID=ArtistID"/>
</cfcomponent>
Versioning
Versioning is a technique that allows you to implement concurrency control fora component. You can specify either
version or timestamp property for a component.
For details, see Optimistic locking.
Note: A component can have only one versioning property, either timestamp or version. If you specify multiple versioning
properties, such as two timestamps, or two versions, or a timestamp and a version, an error is thrown.
Version
Use the version attribute to indicate that the column contains versioned data. The version attribute is useful for long
transactions.
552
Syntax
<cfproperty
name="fieldname"
fieldtype="version"
column="column name"
ormtype="type"
generated="true|[false]"
insert="[true]|false">
Example
To create a simple version property:
<cfproperty name="version" fieldtype="version">
Attribute
Attribute
Req/Opt
Default
column
Optional
fieldtype
Required
generated
Optional
insert
Optional
name
Required
ormtype
Optional
never
int
Description
Time stamp
Use the timestamp attribute to indicate that the column contains time-stamped data. Use the timestamp attribute as
an alternative to the version attribute.
Syntax
<cfproperty
name="fieldname"
fieldtype="timestamp"
column="column name"
generated="true|[false]"
source="[vm]|db">
553
Attribute
Req/Opt
Default
Description
column
Optional
fieldtype
Required
generated
Optional
false
name
Required
source
Optional
string
character
char
short
integer
int
long
big_decimal
float
double
Boolean
yes_no
true_false
text
date
timestamp
binary
serializable
blob
clob
554
Define Relationships
Relationship is the most crucial aspect of ORM. In a relational database, relation between tables are defined using
foreign key. However, in case of objects, relation between two objects is defined using association where one object has
a reference to another. ORM defines how the object relation is mapped to the database relation.
In this topic, relation and association would be used interchangeably.
Before you learn how to define the mapping for relation, it is important to understand few key concepts:
Source object: Object having the reference to the related object is termed as source of the relationship.
Target object: Object being referred or associated is termed as target of the relationship.
Direction and Navigability: In relational database, the relationship is always unidirectional, which implies that you
can navigate from one table to another but not back to the same table. However, object model can be either
unidirectional or bidirectional. A unidirectional association means that source has the reference to the target but the
target does not know about the source. A bidirectional association means that both the objects have reference to each
other and you can navigate from either object to another. In other words, source has a reference to the target and
target also has a reference to the source. This also means that both the objects are source and target at the same time.
To set the association between objects, you need to set the references appropriately. For example, in case of PersonAddress relation, where one person as one address, you need to associate Address to person as:
person.setAddress(address);
At this point, person object knows about the Address object but the address object does not know the person object.
So, this is a unidirectional relation between Person-Address. To make this bidirectional, you need to associate
Person to Address as:
address.setPerson(person);
Multiplicity: This defines how many target entities can a particular source have and how many source entities can
a particular target have. Consider the example of artwork and artist, where an artist has many artwork pieces. In an
object model, an artwork has reference to one artist and an artist has reference to many pieces of artwork. So, for
artwork and artist the multiplicity is many-to-one and for artist and artwork, it is one-to-many. The other two type
of multiplicities are one-to-one and many-to-many.
In this topic, multiplicity would be referred to as the type of relationship.
To indicate that a property defines the relationship between two persistent components, as a result of relationship in
the database table, specify the fieldtype in the cfproperty tag to one of the following:
one-to-one
one-to-many
many-to-one
many-to-many
555
You can also use the link table to establish a relationship. A link table contains the foreign key to both tables that
participate in the relationship. ORM looks for the map key column using the link table and not the target table.
Relationship attributes
This table specifies the attribute details for all the relationship types.
The "Applies to" column indicates the relationship type that the attribute is applicable to; "all" indicates that the
attribute is applicable to all relationship types.
Attribute
Applies to
Re/Opt
Default
batchsize
one-to-many
Optional
optional
many-to-many
cacheuse
one-to-many
many-tomany
cachename
one-to-many
Description
many-to-many
<entityname
>
<relationnam
e>
cascade
all
optional
cfc
all
Required
constrained
one-to-one
Optional
false
fetch
all
Optional
select
fieldtype
all
Required
column
556
Attribute
Applies to
Re/Opt
fkcolumn
all
Optional
Default
Description
Specifies the foreign key column.
In case the relation is established using link table, this specifies
the foreign key column in the link table that references the
primary key of the source object.
If the relationship is established using multiple foreign key
columns (that reference the composite key of the source
table), then you must use comma-separated column
names.Also, the order in which the column names are
specified must match the order of composite keys defined. If
you do not specify any values, then
foreignkeyname
one-to-one
optional
autogenerate Specifies the name of the foreign key constraint. This is used
d
only when the tables are created by ORM.
many-to-one,
many-tomany
index
many-to-one
optional
false
Specifies the name of the index for the foreign key column.
insert
many-to-one
Optional
true
one-to-many
Optional
many-to-many
false
inversejoincolumn
all
Optional
557
Attribute
Applies to
Re/Opt
Default
Description
lazy
all
Optional
true
linkcatalog
all
Optional
linkschema
all
Optional
linktable
all
Required
mappedby
all
Optional
missingrowIgnored
many-to-one,
Optional
false
many-tomany,
Values are:
true
false
(in ColdFusion
9.0.1) one-toone
If the value is true, and the row that is referenced by the foreign
key is missing, it is treated as a null association.
The default is false, in which case an exception is thrown.
name
all
Required
notnull
many-to-one
optional
false
Use this to add the not-null constraint for the foreign key
column when the table is created by ORM.
optimisticlock
all
Optional
true
orderby
one-to-many
Optional
many-to-many
one-to-many
Optional
false
many-to-many
Values are:
true
false
If set to true, it indicates that the collection never changes and
can be cached.
remotingFetch
all
Optional
false
558
Attribute
Applies to
Re/Opt
Default
Description
singularname
one-to-many
optional
property
name
many-to-many
structkeycolumn
one-to-many
many-to-many
type=struct
structkeytype
one-to-many
Optional
many-to-many
For the entire list of data types, see the Data Types section.
type =struct
type
one-to-many
Optional
many-to-many
array
struct
update
many-to-one
Optional
true
unique
many-to-one
optional
false
uniquekey
many-to-one
optional
where
one-to-many
optional
Use this to specify a SQL that will be used to filter the collection
retrieved. See Applying filters on relationship for details.
many-to-many
Use this to add the unique constraint for the foreign key
column when the table is created by ORM. This effectively
makes this relation one-to-one.
Cascade options
In an association, it is cumbersome to apply an action performed on object to the other object. For example, in case of
an Department-Employee one-to-many association, if you add an employee, the same change needs to be updated on
the Department as well. The cascade option in Hibernate allows you to perform such operations.
You can specify the following values in the cascade attribute:
all: Allows you to apply all operations to be cascaded to the associated object.
save-update: If the parent object is saved, the associated objects are saved as well.
delete: Deletes the child object if the delete operation is called on the parent object.
delete-orphan: This is a special kind of cascade option that applies to one-to-many relation only. Deletes all child
all-delete-orphan: Cascades all operations to child objects, and performs delete-orphan action.
refresh: Cascades the refresh action to the child object. The refresh action is used to reload an object and its
collections.
Typically, cascade attribute is not used on a many-to-one or a many-to-many relationship.
559
You can also specify comma separated cascade values in the cascade attribute. For a one-to-one or a one-to-many
relationship, the most common values are all-delete-orphan.
For an association where the child object can continue to exist even if the parent object is deleted, you can apply the
save-update cascade value.
Applying filter on associated objects
In one-to-many and many-to-many relationships, an array or struct is retrieved. Filters can be applied to retrieve a
subset of the associated objects. The filter can be specified in the where attribute, which is an SQL where clause. In a
one-to-many association for artist and artwork:
If you want to retrieve only the unsold artwork for every Artist object, you need to define the mapping as follows:
<cfproperty name="unsoldArts" cfc="Art" fieldtype="one-to-many" fkcolumn="ARTISTID"
where="issold=0">
Inverse
In a bidirectional relationship, the inverse attribute is used on an association property to specify whether an SQL
query should be executed for the association, when persisting the object.
Consider the ART and ARTIST CFCs, which have a bidirectional one-to-many relationship. This means that each ART
object has a reference to the ARTIST object and ARTIST object has a reference to the ART object. While persisting
ARTIST and the associated ART, the relationship can be established in the database from both sides of the object.
Setting inverse=true on one side of the relation tells ORM to ignore this side of relation for executing the SQL.
As a general rule, in a bidirectional relation, one side must set inverse to true. For one-to-many or many-to-one
relation, inverse should be set on the many side of the relation. For example, in ARTIST-ART relation, inverse should
be set to true on the 'art' property in ARTIST.
In many-to-many relation, you can set inverse=true on any side of the relation.
One-to-one relationships
A one-to-one relationship is where the source object has an attribute that references another single target object and
vice-versa. An example of this relationship is the relationship between an employee and the assigned office cubicle,
where one employee has one office cubicle and one office cubicle belongs to only one employee.
A one-to-one relationship between two persistent components are defined using fieldtype value one-to-one.
Syntax:
<cfproperty name="fieldname"
fieldtype="one-to-one"
cfc="Referenced_CFC_Name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns"
cascade="cascade_options"
constrained="true|[false]"
fetch="join|[select]"
lazy="[true]|false">
560
EMPLOYEE.cfc
<cfcomponent persistent="true" table="Employee">
<cfproperty name="id" fieldtype="id" generator="native">
<cfproperty name="firstname">
<cfproperty name="lastname">
<cfproperty name="officecubicle" fieldtype="one-to-one" cfc="OfficeCubicle">
</cfcomponent>
OFFICECUBICLE.cfc
<cfcomponent persistent="true" table="OfficeCubicle">
<cfproperty name="id" fieldtype="id" generator="foreign" params="{property='Employee'}"
ormtype="int">
<cfproperty name="Employee" fieldtype="one-to-one" cfc="Employee" constrained="true">
<cfproperty name="Location">
<cfproperty name="Size">
</cfcomponent>
fieldtype=one-to-one specifies that the property is a one-to-one property.
constrained=true on Employee property in OFFICECUBICLE.cfc, means that a constraint is set on the
561
<cfproperty
name="fieldname"
fieldtype="one-to-one"
cfc="Referenced_CFC_Name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns"
mappedby="Mapped_Field_name_in_referenced_CFC"
cascade="none"
fetch="join|[select]"
lazy="[true]|false">
Note: The mappedby attribute can not be specified with the fkcolumn attribute.
Example
In the EMPLOYEE and OFFICECUBICLE example, OFFICECUBICLE has a foreign key column, EMPLOYEEID.
This foreign key references the primary key of the Employee table. OFFICECUBICLE has an auto-generated primary
key, which does not participate in the relationship.
EMPLOYEE.cfc
<cfcomponent persistent="true" table="Employee">
<cfproperty name="EmployeeID" fieldtype="id" generator="native">
<cfproperty name="firstname">
<cfproperty name="lastname">
<cfproperty name="officecubicle" fieldtype="one-to-one" cfc="officecubicle"
mappedby="Employee">
</cfcomponent>
OFFICECUBICLE.cfc
<cfcomponent persistent="true" table="officecubicle">
<cfproperty name="id" fieldtype="id" generator="native">
<cfproperty name="Employee" fieldtype="one-to-one" cfc="Employee" fkcolumn="EmployeeID">
<cfproperty name="Location">
<cfproperty name="Size">
</cfcomponent>
In OFFICECUBICLE entity, fkcolumn="EmployeeID" specifies that EmployeeID is the foreign key column in
OFFICECUBICLE table.
mappedby="Employee" specifies that the one-to-one relationship is with the foreign-key property 'EMPLOYEE' in
OFFICECUBICLE entity and not with its primary key.
One-to-many relationship
A one-to-many relationship is where the source object has field that stores a collection of target objects. These target
objects may also have an inverse relationship back to the source object. This relationship is established by having a
foreign key in the target table that maps to the primary key of the source table.
An example of a one-to-many relationship is the relation between artist and art, where the artist has many artwork
pieces.
562
A one-to-many relationship between two persistent components is defined using the fieldtype value one-to-many
in the cfproperty tag. The source object contains a collection of target objects. ColdFusion allows the collection to
be one of the following types:
Array
Struct
This collection is a persistence aware collection. Any addition or deletion from this collection is automatically persisted
in the database.
Array
An Artist object can contain the Art objects as an array. To define this mapping in the CFC, use the following syntax:
Syntax
<cfproperty
name="field_name"
fieldtype="one-to-many"
cfc="Referenced_CFC_name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns "
type="array"
orderby="order_by_string"
cascade="cascade_options"
lazy="[true]|false|extra"
fetch="join|[select]"
inverse="true|[false]"
batchsize="N"
optimisticlock="[true]|false"
readonly="true|[false]">
For the artist-art example, the relationship property in Artist.cfc is defined as follows:
<cfproperty name="art" type="array" fieldtype="one-to-many" cfc="Art" fkcolumn="ARTISTID">
type-array specifies that the artist object will contain art objects in an array.
fkcolumn="ArtistID" specifies that the foreign key column is ARTISTID that references the primary key of
ARTIST table.
Struct
An Artist object can contain the Art objects as a struct. The key would be any column in the ART table (usually the
primary key or a unique key). The value would be the Art object. To define this mapping, use the following syntax.
Syntax
563
<cfproperty
name="field_name"
fieldtype="one-to-many"
cfc="Referenced_CFC_name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns"
type="struct"
orderby="order_by_String"
structkeycolumn = "Structure_Key_Column"
structkeytype="ormtype"
cascade="cascade_options"
lazy="[true]|false|extra"
fetch="join|[select]"
inverse="true|[false]"
batchsize="N"
optimisticlock="[true]|false"
readonly="true|[false]">
For the artist-art example, you can define the relationship property as:
<cfproperty name="art" type="struct" fieldtype="one-to-many" cfc="Art" fkcolumn="ARTISTID"
structkeytype="int" structkeycolumn="ArtID">
type=struct specifies that the artist object will contain art objects in a struct.
table.
Many-to-one relationship
A many-to-one relationship is the inverse of a one-to-many relationship. In this relationship, many source objects can
reference the same target object.
An example of this relationship is the relation between Art and Artist, where many Art are created by the same Artist.
This relationship is established with the foreign key in the source table that references the primary key in the target
table.
A many-to-one relationship between two persistent components is defined using the fieldtype value many-to-one
in the cfproperty tag.
564
Syntax
<cfproperty
name="fieldname"
fieldtype="many-to-one"
cfc="Referenced_CFC_Name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns"
column="Foreign_Key_Column"
mappedby="Mapped_Field_name_in_referenced_CFC"
cascade="cascade_options"
fetch="join|[select]"
lazy="true|false"
insert="[true]|false"
update="[true]|false"
optimisticlock="[true]|false"
missingrowIgnored="true|[false]">
For the art-artist example, the relationship in the ART.cfc can be defined as:
<cfproperty name="artist" fieldtype="many-to-one" fkcolumn="artistid" cfc="Artist">
fkcolumn="ARTISTID" indicates that the foreign key column in Art table references the primary key ARTISTID of
ARTIST table.
Many-to-many relationships
A many-to-many relationship is where the source objects contain a collection of target objects and the target objects
in turn contain a collection of source objects.
An example of a many-to-many relationship is the relation between Order and Product, where an order has many
products and a product has many orders.
This relationship is established by using a third table called a 'LinkTable'. The LinkTable contains the foreign key to
both the tables participating in the relation. ORM looks for the map key column in the LinkTable and not the target
table.
In the preceding example of Order-Product, a many-to-many relationship is established by using LinkTable.
A many-to-many relationship between two persistent CFCs is defined using the fieldtype="many-to-many" value
in the cfproperty tag.
Note: If the fkcolumn name is not specified, ORM generates the fkcolumn name in the "#relationName#_ID" format.
Syntax
Order.cfc
565
<cfproperty
name="fieldname"
fieldtype="many-to-many"
cfc="fully qualified name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or a composite key with comma-separated primary key columns"
mappedby="Property in the target component that is referenced by fkcolumn in join table"
type="[array]|struct"
orderby="order by String
structkeycolumn="The structure key column name"
structkeydatatype="datatype".
cascade="cascade options" inverse="true|[false]" lazy = "[true]|false" [optional]
fetch="join|[select]" [optional] batchsize="integer" optimisticlock="[true]|false"
readonly="true|[false]"
missingrowIgnored="true|[false]">
For the Order-Product example, the many-to-many relationship is established using a third table "OrderProduct" that
has two foreign keys: OrderId and ProductId. OrderId references the primary key orderId in the order table, and
ProductId references the primary key productId in the Product table. This relationship can be defined as follows:
Order.cfc
<cfproperty
name="products"
fieldtype="many-to-many"
CFC="Product"
linktable="Order_Product"
FKColumn="orderId"
inversejoincolumn="productId"
lazy="true"
cascade="all"
orderby="productId">
Product.cfc
<cfproperty
name="orders"
fieldtype="many-to-many"
CFC="Order"
linktable="Order_Product"
FKColumn="productId"
inversejoincolumn="orderId"
lazy="true"
cascade="all"
orderby="orderId">
The fkcolumn here is the foreign key in the link table that references the primary key of the source table.
InverseJoinColumn is the foreign key in the link table that references the primary key of the target table. This
attribute can also take a composite key value, for example you can specify inversejoincolumn=field1, field2, where
field1 and field2 form the composite key.
566
Advanced mapping
Collection Mapping
Collection mapping is similar to a one-to-many relationship mapping. However, in collection mapping, you have a
collection of values instead of a collection of persistent target objects.
Consider the Artist-Art tables. If you want each Artist object to contain an array of artwork names instead of artwork
objects, collection mapping should be used.
To define collection mapping in the CFC, use fieldtype="collection" in the cfproperty tag.
The collection can either be Array or Struct.
Array
Syntax
name="field_name"
fieldtype="collection"
type="array"
table="table_name"
fkcolumn="foreign_key_column_name"
elementtype="ormtype"
elementColumn="column_name from the link table that should be
used for populating"
orderby="order by string"
lazy = "true|[false]"
readonly="true|[false]"
optimisticlock="[true]|false"
batchsize="batch size">
Example
If each Artist object contains an array of artwork names instead of artwork objects, this mapping can be defined in
Artist.cfc as:
<cfproperty name="artNames" fieldtype="collection" type="array" table="ART"
fkcolumn="ARTISTID" elementcolumn="ARTNAME" elementtype="string">
Attribute
Attribute
Req/Opt
Default
batchsize
Optional
elementColumn
Required
elementtype
Optional
fieldtype
Required
String
Description
567
Attribute
Req/Opt
fkcolumn
Optional
Default
Description
The foreign key column in the specified
table.
If you do not specify the foreign key
column and useDBForMapping is true
in ormsettings, ColdFusion
automatically determines a foreign key
column after inspecting the database.
lazy
Optional
true
name
Required
optimisticlock
Optional
orderBy
Optional
readonly
Optional
true
false
If set to true, it indicates that the collection
never changes and can be cached.
table
Required
type
Optional
Struct
Syntax
<cfproperty
name="field_name"
fieldtype="collection"
type="struct"
table="table_name"
fkcolumn="foreign_key_column_name"
structkeycolumn="column in the target table to be used as key in the struct"
structkeytype="ormtype of the key in the struct"
elementtype="ormtype of the valye in the struct"
elementColumn="column name from the table that should be used in
value of struct"
orderby="order by string"
lazy = "[true]|false"
readonly="true|[false]"
optimisticlock="[true]|false"
batchsize="batch size">
568
Attribute
Req/Opt
Default
Description
batchsize
Optional
elementcolumn
Required
elementtype
Required
Data type of the value. See ORM data types for details.
fieldtype
Required
Should be a collection.
fkcolumn
Optional
lazy
Optional
true
name
Required
optimisticlock
Optional
true
false
orderby
Optional
readonly
Optional
Value are:
true
false
If you set it to true, the collection never changes and
can be cached.
structkeycolumn
Required
structkeyType
Required
table
Required
type
Optional
Inheritance mapping
If the object you need to persist has a hierarchy, the CFCs of that object hierarchy need to be mapped to the relational
tables such that the entire hierarchy is persisted.
There are multiple strategies followed for inheritance mapping:
569
Payment Table
Payment (extended by)
Check Payment
CreditCard Payment
In the preceding figure, discriminatorColumn is PaymentType. Depending on the values of PaymentType whether
it is credit card or check, the row is represented as a CreditCardpayment or checkPayment object respectively.
The following example illustrates how you can model the table per hierarchy:
Payment.cfc (parent class)
<cfcomponent persistent="true" table="Payment" discriminatorColumn="paymentType">
<cfproperty name="id">
<cfproperty name="amount">
</cfcomponent>
CreditCardPayment.cfc
<cfcomponent persistent="true" extends="Payment" table="Payment" discriminatorValue="CCard">
<cfproperty name="cardNo">
<cfproperty name="cardType">
</cfcomponent>
CheckPayment.cfc
<cfcomponent persistent="true" extends="Payment" table="Payment" discriminatorValue="check">
<cfproperty name="checkNo">
<cfproperty name="bankName">
<cfproperty name="city">
</cfcomponent>
570
CreditCardPayment
paymentID
cardNo
cardType
CreditCardPayment class
paymentID
checkNo
bankName
city
In the preceding figure, the tables are joined by join column paymentId. You can model the tables as follows:
Payment.cfc
<cfcomponent persistent="true" table="Payment">
<cfproperty name="paymentId">
<cfproperty name="amount">
</cfcomponent>
CreditCardpayment.cfc
<cfcomponent persistent="true" extends="Payment" table="CreditCardPayment"
joinColumn="paymentId">
<cfproperty name="cardNo">
<cfproperty name="cardType">
</cfcomponent>
CheckPayment.cfc
<cfcomponent persistent="true" extends="Payment" table="CheckPayment" joinColumn="paymentId">
<cfproperty name="checkNo">
<cfproperty name="bankName">
<cfproperty name="city">
</cfcomponent>
When an object of type CreditCardPayment is persisted, the property amount is stored in the payment table and the
properties cardNo and cardType are stored in the CreditCardPayment table. The primary key of the
CreditCardPayment remains the same as the primary key of the Payment table.
Table per subclass with discriminator
This model is similar to the table per subclass without discriminator strategy except that there is a discriminator
column in the parent table. In addition, the child components has a disciminatorValue attribute in the
cfcomponent tag.
The following example demonstrates the table per subclass with discriminator attribute:
Payment.cfc
571
CreditCardPayment.cfc
<cfcomponent persistent="true" extends="Payment" table="CreditCardPayment"
joinColumn="paymentId" discriminatorValue="CCard">
<cfproperty name="cardNo">
<cfproperty name="cardType">
</cfcomponent>
CheckPayment.cfc
<cfcomponent persistent="true" extends="Payment" table="CheckPayment" joinColumn="paymentId"
discriminatorValue="Check">
<cfproperty name="checkNo">
<cfproperty name="bankName">
<cfproperty name="city">
</cfcomponent>
When an object of type CreditCardPayment is persisted, the property amount is stored in the payment table and the
properties cardNo and cardType are stored in the CreditCardPayment table. The primary key of CreditCardPayment
remains the same as the primary key of the Payment table. The value of PaymentType is the value of
disciminatorColumn attribute of the respective object.
Embedded mapping
This mapping is used when a CFC has an embedded object which also needs to be persisted along with the parent's
data. The CFC of the embedded object must have the attribute embedded set to "true" on the cfcomponent tag.
Important: The embedded object cannot be a persistent object. This feature is supported only when the hibernate
mapping is explicitly defined in the hibernate mapping file (.hbmxml files).
Name
FirstName
LastName
Title
Employee
EmployeeID
EmployeeName
Designation
The diagram shows two CFCs Employee and Name where EmployeeName field of the Employee.cfc is an object of
Name.cfc. In the database, both these objects are persisted in the Employee table as a single row. Name object itself
does not have its own identity. This mapping can be modeled as follows:
name.cfc
<cfcomponent embedded="true">
<cfproperty name="FirstName">
<cfproperty name="LastName">
<cfproperty name=" Title">
</cfcomponent>
employee.cfc
572
<cfcomponent persistent="true">
<cfproperty name="EmployeeID">
<cfproperty name="EmployeeName">
<cfproperty name="Designation">
</cfcomponent>
employee.hbmxml
<hibernate-mapping >
<class name="cfc:Employee" table="Employees">
<id name="EmployeeID" type="integer" column="EmployeeID">
<generator class="native"/>
</id>
<component name="EmployeeName" class="cfc:Name">
<property name="LastName" type="string" column="LastName"/>
<property name="FirstName" type="string" column="FirstName"/>
<property name="Title" type="string" column="Title"/>
</component>
<property name="Designation" type="string" column="Designation"/>
</class>
</hibernate-mapping>
If the persistent CFC has a collection of embedded objects, then this mapping also has to be defined in the XML as
shown in the following example. Here, employee object has a collection of IMData objects. Note that the IMData object
is not persistent.
employee.cfc
<cfcomponent
<cfproperty
<cfproperty
<cfproperty
<cfproperty
</cfcomponent>
persistent="true">
name="EmployeeID">
name="EmployeeName">
name= "IMIDs" type="array">
name="Designation">
IMData.cfc
<cfcomponent embedded="true">
<cfproperty name="type">
<cfproperty name="ID">
</cfcomponent>
employee.hbmxml
<hibernate-mapping>
<class name="cfc:Employee" table="Employees">
<id name="EmployeeID" type="integer" column="EmployeeID">
<generator class="native"/>
</id>
<property name="EmployeeName" type="string" column="EmployeeName"/>
<bag name="IMIDs" table="IMData" lazy="true">
<key column="EmployeeID" />
<composite-element class="cfc:IMData">
<property name="type" type="string" column="Type"/>
<property name="ID" type="string" column="ID"/>
</composite-element>
</bag>
<property name="Designation" type="string" column="Designation"/>
</class>
</hibernate-mapping>
573
Emp.cfm
<cfscript>
employee = EntityNew("Employee");
employee.setEmployeeName("Dan Watson");
imdata1 = new IMData();
imdata1.setType("IMClient1");
imdata1.setID("msngrId1");
imdata2 = new IMData();
imdata2.setType("IMClient 2");
imdata2.setID("msngrId2");
employee.setIMIDs([imdata1, imdata2]);
EntitySave(employee);
</cfscript>
For more details on component mapping in hibernate, see Component Mapping in Hibernate Reference Guide.
The entityname attribute is optional. If you do not specify this attribute, it takes the component name, by default.
For example, for the component artgallery.art, the value of the entityname attribute is Art, by default.
The entity name must be unique for an application. If there are two components with the same name (even if they
are in different packages), specify different entity names for each of these components.
574
column="artistid" name="artist"/>
index.cfm
<cfset artists = entityLoad("Artist")>
<cfdump var="#artists#">
The columns are fetched only as column properties. Relationship, timestamp, or version field are not added.
Limitations
If the mapping file for the CFC exists, then the properties are not added automatically.
In the case of inheritance, properties are not added to the CFC automatically.
575
Generated accessors
As described in Define ORM mapping, the persistent fields for an object are defined in the CFC using cfproperty.
ColdFusion generates the accessor methods (getter and setter) for each property in the CFC that can be invoked. For
more information, see Implicit Get and Set Functions. For example, if a property is defined in Artist as follows:
<cfproperty name="firstName" >
setFirstName(firstName)
getFirstName()
You can invoke these methods like regular methods in the CFC. For a property, the generated setter saves the value for
the property in the object's VARIABLES scope. The generated getter retrieves the value of the property from the
VARIABLES scope. ORM always uses the property value from the VARIABLES scope. That is, while saving the object's
data in the table, ORM retrieves the value of the property from VARIABLES scope. While populating the object after
reading from the table, ORM puts the property's value in the VARIABLES scope.If you define your own accessor
methods for a property, store the property value in the VARIABLES scope for ORM to access it.
add<relationship_property_name>()
This method is generated for one-to-many and many-to-many relationships. The method adds the given object to
the association collection (array or struct) of the component. For a bidirectional relationship, this method does not
set the association on the other end.
For type="array", the method signature is:
add<relationship_property_name>(<associated_object>)
boolean remove<relationship_property_name>()
This method is generated for one-to-many and many-to-many relationships. The method removes the object from
the associated collection (array or struct) of the component. If the associated object was removed from the
collection successfully, then true is returned. For a bidirectional relationship, this method does not remove the
association from the other end.
For type="array", the method signature is:
boolean remove<relationship_property_name>(<associated_object>)
576
boolean Has<relationship_property_name>()
This method is generated for all the relationships. For one-to-many and many-to-many, this method checks
whether the association collection is empty. If the association collection is empty, it will return true. For one-to-one
and many-to-one, this method checks whether the associated object exists.
boolean Has<relationship_property_name>(<associated_object>)
This method is generated for one-to-many and many-to-many relationships. The method checks whether the given
associated object is present in the association collection. If it is present, it returns true.
For type="array", the method signature is
boolean has<relationship_property_name>(<associated_object>)
Example
Consider the following example of artists (ARTISTS table) and artwork (ART table), where the artist forms a one-tomany relationship with artwork.
Artist.cfc
<cfcomponent persistent="true" schema="APP" table="Artists">
<cfproperty name="artistid" fieldtype="id"/>
<cfproperty name="firstname"/>
<cfproperty name="lastname"/>
<cfproperty name="state"/>
<cfproperty name="art" fieldtype="one-to-many" cfc="Art" fkcolumn="ArtistID" >
</cfcomponent>
Art.cfc
<cfcomponent persistent="true" schema="APP" table="Art">
<cfproperty name="artid" fieldtype="id"/>
<cfproperty name="artname"/>
<cfproperty name="issold"/>
</cfcomponent>
In this example Artist has a relation field art with Art. The following methods are implicitly added to the Artist object:
addArts(Art art)
booleanremoveArts(Art art)
booleanhasArts()
booleanhasArts(Art art)
The attribute singularName provides the flexibility to change the name of the generated relationship methods. For
example, if the relationship property of Artist is specified as follows:
<cfproperty name="art" fieldtype="one-to-many" cfc="Art" fkcolumn="ArtistID"
singularName="Art">
addArt(Art art)
removeArt(Art art)
hasArt()
577
hasArt(Art art)
Insert (Create)
Update
Retrieve
Delete
Once the object relational model is defined in a ColdFusion application, you can perform CRUD operations on the
objects directly using the methods provided by ColdFusion ORM. ColdFusion ORM, in turn, takes care of persisting
the object in the database.
Create entities
EntityNew
Creates an object for persistent CFC with the given entity name. This is similar to CreateObject but it uses entityname
whereas CreateObject takes CFC name. If there is no CFC defined in the application with the given entityname, an
error will be thrown.
If the persistent CFC has an init method, then the function EntityNew calls the init method while creating the
object.
Syntax
<entity> EntityNew("<entityName>")
Save entities
EntitySave
Saves or Updates the data of the entity and all related entities to the database.
ColdFusion automatically tries to find if a new record should be inserted or an existing record be updated for the given
entity. If forceinsert=true, then ColdFusion always tries to insert the entity as a new record.
Calling this method may not run the insert/update SQL immediately. It is possible that various SQL statements are
queued and then run as a batch for performance reasons. The SQL statements are run when the ORM session is
flushed.
Syntax
EntitySave(entity, [forceinsert])
Parameter
Description
entity
forceinsert
If true, then ColdFusion always tries to insert the entity as a new record.
578
Example:
<cfset
<cfset
<cfset
<cfset
artist = EntityNew("Artist")>
artist.setFirstName("Marcia")>
artist.setlastName("Em")>
EntitySave(artist)>
Update objects
EntitySave
The method to update an object is the same as saving an object. Load the object that needs to be updated, make updates,
and save the object.
Syntax
EntitySave(entity, [forceinsert])
Example
The following example changes the first name of an artist with an Artist ID 1:
<cfset artist1 = EntityLoad("Artist", 1, true)>
<cfset artist1.setFirstName("Garcia")>
<cfset EntitySave(artist1)>
Read/Load objects
Entities are loaded using the EntityLoad methods. All EntityLoad methods take the entity name as input.
If the persistent CFC has an init method, the methods call the init method while creating objects.
Syntax
EntityLoad (entityname)
EntityLoad (entityname, id [, unique])
EntityLoad (entityname, filtercriteria [,unique]
EntityLoad(entityname, filtercriteria, sortorder [, options])
EntityLoadByExample(sampleentity [, unique])
EntityReload(entity)
Examples
EntityLoad (entityname)
Loads and returns an array of entities of the specified entity name. For example, to retrieve all the objects of the
artist CFC:
<cfset artist = EntityLoad('ARTIST')>
Loads and returns an entity whose Primary key's value is id. The entity is returned as an array by default. If unique
is true, then the entity is returned.
If the entity has a composite key, then the id has to be specified as key-value pairs (ColdFusion struct).
Example 1:
This example loads the Artist object with PK 100 and returns a single-element array containing the artist object.
<cfset artistArr = EntityLoad('Artist', 100)>
Example 2:
579
This example loads the Artist object with PK 100 and returns the artist object.
<cfset artistobj = EntityLoad('Artist', 100, true)>
Example 3:
This example loads the OrderDetail object which has the composite key OrderID=100 and ProductID=1 and
returns the orderdetail object.
<cfset orderDetail = EntityLoad('orderdetails', {OrderID=100, ProductID=1}, true)>
Loads and returns an array of entities of the given entity name that matches the filtercriteria.
filtercriteria is a key-value pair (ColdFusion struct) of property names and its values. If there are more than
one key-value pair in filtercriteria, then they always use the AND operator. If you are sure that only one record
exists that matches this filtercriteria, unique=true can be specified so that a single entity is returned instead
of an array. If unique=true and multiple records are returned, then an exception occurs. For example, to retrieve
details of all artists that have state CA:
<cfset artistsFromCA = EntityLoad('Artist', {state="CA"})>
To retrieve a unique object, specify unique= "true". If more than one object satisfies the condition, an exception
occurs.
This example loads the artist object whose firstName is "Austin" and lastname is "Weber".
<cfset artist = EntityLoad('artist', {firstname="Austin", lastname="Weber"}, "true")>
EntityLoad(entityname,filtercriteria,sortorder[, options])
Loads and returns an array of entities that satisfy the filtercriteria that is sorted as specified by the sortorder
parameter.
filtercriteria is a key-value pair (ColdFusion struct) of property names and its values. If there are more than
one key-value pairs in filtercriteria, then they always use the AND operator.
sortorder is a string, and should be specified in the following syntax:
Certain configuration options can be input as name-value pairs as options argument. Several options can be
specified to control the behavior of entity retrieval.
offset: Specifies the start index of the resultset from where it has to start the retrieval.
cacheable: Whether the result of this query is to be cached in the secondary cache. Default is false.
580
timeout: Specifies the timeout value (in seconds) for the query.
Example
To load first 5 artists whose state is "CA" that are sorted on the firstName.
<cfset artists = EntityLoad("Artist",{state='CA"}, "FirstName", {maxResults=5})>
EntityLoadByExample(sampleentity [,unique])
Loads and returns an array of objects that match the sampleentity. The filter criteria is constructed by ANDing
all the non-null properties of the sampleentity.For example, to retrieve an array of objects matching the specified
values:
<cfset
<cfset
<cfset
<cfset
If you are sure that only one record exists that matches the specified filtercriteria, you can specify
unique=true so that a single entity is returned instead of an array. If unique=true and multiple records are
returned, then an exception occurs.
EntityReload(entity)
Reloads data for an entity that is already loaded in this session. This method refetches data from the database and
repopulates the entity.
Delete objects
EntityDelete
This method deletes the record from the database for the specified entity. Depending on the cascade attribute specified
in the mapping, it also deletes the associated objects.
Syntax
EntityDelete(entity)
Example
For example, to delete an Artist with ArtistID 5:
<cfset artist = EntityLoad('artist', 5, true)>
<cfset EntityDelete(artist)>
name of the properties are used as the query column names. Use the optional parameter Entity_name to return the
query of the given entity in the case of inheritance mapping. All the objects in the input array should be of the same
type. Relationship properties are not be included in the result query.
Syntax
EntitytoQuery (orm_object, [entity_name])
EntitytoQuery (orm_object_array, [entity_name])
581
Example 1
<cfset artists = EntityLoad("Artist")>
<cfset artistQuery = EntityToQuery(artists)>
Example 2
<cfset creditCardPayments = EntityLoad("CreditCardPayment")>
<cfset paymentQuery = EntityToQuery(creditCardPayments, "payment")>
Merge entities
EntityMerge
To attach an entity to the current ORM session you can use the entitymerge function. It copies the state of the given
object onto the persistent object with the same identifier and returns the persistent object.
If there is no persistent instance currently associated with the session, it is loaded. The given instance is not associated
with the session. You need to use the returned object from this session. For details, see EntityMerge in CFML Reference.
Using queries
ColdFusion lets you use HQL (Hibernate Query Language) to run queries directly on the database. If you are familiar
with HQL, you can use it for running complex queries.
In general, use HQL in the following scenarios:
The query is not specific to a particular object but only to some fields in the object.
To retrieve some fields of the object without loading the object.
When you use table joins.
When you use aggregate functions like min, max, avg, and count.
To retrieve entities by specifying a filter that needs to use operators other than AND.
For more information on HQL, see
www.hibernate.org/hib_docs/reference/en/html/queryhql.html
The HQL methods return a single or multi-dimensional array of values or entities, based on what the HQL query
returns.
If you are sure that only one record exists that matches this filter criteria, specify unique=true so that a single entity
is returned instead of an array. You can use unique=true to suppress the duplicate records from the query result.
Note: entityname and properties used in HQL are case sensitive.
The following HQL methods are available:
ORMExecuteQuery(hql, [params] [,unique])
ORMExecuteQuery(hql, [,unique] [, queryoptions])
ORMExecuteQuery(hql, params [,unique] [,queryOptions])
ORMExecuteQuery (hql, params, boolean unique, Map queryOptions)
582
offset: Specifies the start index of the resultset from where it has to start the retrieval.
cacheable: Whether the result of this query is to be cached in the secondary cache. Default is false.
timeout: Specifies the timeout value (in seconds) for the query
Note: If the query returns an object or an array of objects, the init method of the persistent CFC is called (if available).
Examples
To retrieve an array of artwork objects from the ART table:
<cfset art = ORMExecuteQuery("from ART")>
To retrieve an array of artwork objects that have a price greater than 400 dollars:
<cfset art = ORMExecuteQuery("from ART where price > 400")>
To retrieve an array of ten artist objects starting from the fifth row in the query result:
<cfset artists = ORMExecuteQuery("from Artist", false, {offset=5, maxresults=10, timeout=5})>
To retrieve an array of objects with a price id equal to 40, and price lesser than 80 dollars:
<cfset artists = ORMExecuteQuery("from ART where priceid > ? and price < ?", [40, 80])>
583
Note: In case of more than one parameter, values are picked up based on the parameter sequence, for example, the first
parameter will be replaced by first value and second parameter will be replaced by second value.
Examples: named parameters
This type of ORMExecuteQuery lets you pass named parameters to the query. The placeholder for the parameter should
be a name and should start with ":" as in ":age" or ":id". The values to the names should be passed as key-value pairs.
For example, to retrieve artist details of all artists whose reside in USA and are also citizens of USA, your code should
look like this:
<cfset USArtists = ORMExecuteQuery("from ARTIST where country=:country and
citizenship=:country", {country='USA'})>
<cfset orderDetail = ORMExecuteQuery("from Orders where OrderID=:orderid and
ProductID=:productid", {orderid=1, productid=901}, true)>
Note: Built-in functions to obtain the data such as getFirstName() or getLastName() cannot be used if you are using select
queries with specific column names. The result will be returned as an array object and values can be retrieved using array
index.
Example: order by
This type of ORMExecuteQuery lets you retrieve sorted data from a data source using the order by clause. For example,
to sort the data from the Artist table by firstname, use the following code:
<cfset artist = ORMExecuteQuery('FROM Artist ORDER BY firstname ASC', false, {maxresults=5} )>
<cfloop array="#artist#" index="artistObj">
<cfoutput>Name = #artistObj.getFirstName()#
#artistObj.getLastName()#<br></cfoutput>
<br>
</cfloop>
584
Example: expressions
This type of ORMExecuteQuery lets you retrieve data using expressions such as mathematical operators, logical
operators, binary comparisons, and many others.
For example, the following code is used to retrieve the price of an artwork, which is greater than or equal to 10000 along
with the name and description of the artwork.
<cfset artArr = ORMExecuteQuery("from Art where price>=10000")>
<cfloop array="#artArr#" index="artObj">
<cfoutput>
Art Name = #artObj.getArtName()#<br>
Description = #artObj.getDescription()#<br>
Price = #artObj.getPrice()#<br>
</cfoutput>
<br>
</cfloop>
Using Hibernate transaction: User has full control and ColdFusion does not intervene. The application has to
flush/close the session and commit/rollback the transaction.
For more information on transactions, go to the following URL:
http://community.jboss.org/wiki/sessionsandtransactions
Using CFTransaction: ColdFusion manages the transaction. Since a transaction cannot be distributed (across
different data sources), application must ensure that the changes made in the transaction affect only one Hibernate
session. That is, only one data source.
ColdFusion allows reading of data from other sessions (data source) in a transaction but changes must be made in
only one session. Multiple dirty sessions at any time in the transaction can result in exceptions and the transaction
is rolled back. Before transaction begins, all existing sessions in the request are flushed. The previous session (if any)
is reused.
When the transaction is committed, the dirty session is automatically flushed (before committing the transaction).
When the transaction is rolled back, the changed session cannot be used any longer because it can cause rolled back
data to get committed later. Therefore, the session participating in the transaction is cleared when transaction is
rolled back.
A description of transaction is beyond the scope of this document. For more information on transactions, see the
hibernate documentation.
To run the ORM methods inside a transaction, they must be inside <cftransaction>. A simple example snippet of
using ORM with <cftransaction> is as follows:
585
<cftransaction>
<cfset acct1 = EntityLoad("Account", "101")>
<cfset acct2 = EntityLoad("Account", "102")>
<cfset acct1.debit(1000)>
<cfset acct2.credit(1000)>
<cfset EntitySave(acct1)>
<cfset EntitySave(acct2)>
</cftransaction>
Because we have not called commit on the <cftransaction> specifically, it is automatically committed when the
<cftransaction> ends.
All <cftransaction> semantics including savepoint, multiple rollbacks, multiple commits, and nested transactions
work with ORM. You can also have both queries and ORM in the same <cftransaction>.
When <cftransaction> begins, any existing ORM session is flushed and closed, and a new ORM session is created.
The <cftransaction> can be committed or rolled back using appropriate ColdFusion tags in <cftransaction>.
When the transaction ends and has not been committed or rolled back explicitly, it is automatically committed and
the ORM session is closed. If there is any error inside the transaction, without any exception handling, the transaction
is rolled back.
For more details on <cftransaction>, see the CFML Reference Guide.
Note: Even if ORMFlush() is called explicitly inside a <cftransaction> tag, the SQL runs but the data is committed only
when the transaction commits.
Behavior in ColdFusion 9
Changed behavior
Optimistic locking
A <cftransaction> could prevent scalability in highly concurrent applications because it locks a database for a
transaction that could run for a longer time. Also, a transaction cannot run beyond the duration of a request. There
can be scenarios where an object is loaded in one request and the same instance is updated in another request or by
another application. In this scenario, the application needs to maintain the transaction semantics and prevent the
update if the row has been modified by some other request. This can be achieved by using optimistic concurrency
control, which allows high concurrency in your application along with high scalability.
Optimistic concurrency control uses either number-based or timestamp-based versioning approach. In a numberbased approach, a version number is incremented and for the timestamp approach, a timestamp is set to the current
time whenever the object is modified. It must be noted that version increment or timestamp updation is managed by
Hibernate and is not triggered at the database level.
Using version: To use optimistic concurrency control using version numbers, add a property with
fieldtype='version' in your CFC.
For example:
586
/**
* @persistent
* @table Users
*/
component{
property name="id" fieldtype="id" datatype="int" generator="native";
property string fname;
property string lname;
property name="version" fieldtype="version" datatype="int" ;
}
Whenever a user object is updated, its version number is automatically incremented. The version number is used
in the SQL update statement in such a way that updating proceeds only when the version number has not been
changed by some other request or some other application.
In case updating fails because the version number was changed outside the current session, an error is thrown
specifying that the session contained stale data.
Using timestamp: To use optimistic concurrency control using timestamp, add a property with
fieldtype="timestamp" in your CFC.
For example:
/**
* @persistent
* @table Users
*/
component{
property name="id" fieldtype="id" datatype="int" generator="native";
property string fname;
property string lname;
property name="lastModified" fieldtype="timestamp";
}
Whenever a user object is updated, its timestamp is automatically set to the current time. Sometimes this is
preferred over version because it also tells you when the user object was last modified.
In case updating fails because the timestamp was changed outside of the current session, an error is thrown
specifying that the session contained stale data.
If you do not have version or timestamp properties in your object, it is still possible to use optimistic locking, but only
for objects that are retrieved and modified in the same ORM session. For optimistic locking of detached objects
(objects that were loaded in some other request/ORM session), you must use a version number or timestamp.
To use optimistic locking for objects that do not have version or timestamp, you need to set attribute 'optimisticlock' on the CFC. This attribute can take the following values:
all: This means that all the properties are included in the where clause of update query.
dirty (default): This means that only the modified properties are included in the where clause of the update query.
version: This means that only the version field is included in the where clause of update query.
none: This means that none of the properties are included in the where clause, which in effect means that optimistic
587
/**
* @persistent
* @table Users
* @optimistic-lock all
*/
component{
property name="id" fieldtype="id" datatype="int" generator="native";
property string fname;
property string lname;
}
Apart from defining optimistic lock control at the CFC level, you can also define it at the property level using
'optimisticlock' (true|false: default true) attribute.
You can specify optimisticlock=true for a property to acquire optimistic lock when the property is updated. Setting
this attribute determines whether a version increment will occur when the property is dirty.
In case of one-to-many and many-to-many association, if the state of the collection changes, then version of the
corresponding entity is incremented. It is advised that you disable this setting for one-to-many associations.
Performance optimization
Lazy Loading
Optimizing SQL queries enhances the performance of any data-centric application. Some of the common approaches
used to optimize SQL queries are:
Avoid round trips to the database and fetch all required data for an operation using a single SQL query using Joins.
Fetch only required data to reduce the load on the database
SQL queries are generated and executed by the underlying ORM engine. Therefore, Hibernate provides various hooks
to optimize SQL. The fetching strategy is one of the most important hooks, which defines the data that to be fetched,
the time of fetching the data, and the way in which it needs to be fetched.
There are four strategies for loading an object and its associations.
Immediate fetching
Lazy fetching
Eager fetching
Batch fetching
Note: If memory tracking is enabled on a server, it accesses each field of the object to compute its size. As a result, even
lazy fields are accessed causing the lazy fields to get loaded immediately.
Immediate fetching
In this strategy, the associated object is fetched immediately after the owning entity is fetched, either from the database
using a separate SQL query or from the secondary cache. This is not an efficient strategy to use, unless the associated
object is cached in the secondary cache or when separate queries are more efficient than a Join query. You can define
this strategy by setting lazy="false" and fetch="select" for the relationship property definition in the CFC.
<cfproperty name="art" fieldtype="one-to-many" cfc="ART" fkcolumn="ARTISTID" lazy="false"
fetch="select">
588
With this strategy, on loading the artists object, its art object is loaded immediately using a separate SQL query. As a
result, this strategy is extremely vulnerable to 'N+1 Select problem'.
Lazy fetching
In this strategy, the associated object or collection is fetched only when required. Although you need to send a new
request to the database each time you need data, this strategy controls how much of data is loaded and when is it
loaded. This helps in reducing the database load.
When you load an entity, by default, ColdFusion ORM loads the entitys data but relations and any mapped collections
and are not loaded. They are loaded only when you want to load them by calling the getter method. Therefore, the
relations and collection mappings are lazily loaded. For example, when the artist object is loaded, all its artworks are
not loaded and they are loaded only when getarts() is called.
ColdFusion ORM provides three types of lazy loading for relationships:
lazy: This is the default lazy loading that applies to collection mapping, one-to-many and many-to-many
relationship. In this case, when you call the accessor for the collection/relation, the collection is fully loaded. So,
when you call EntityLoad() for a particular artist, its artworks are not loaded at that time. When you call
artist.getarts(), all the art object belonging to the artist will get loaded. This is achieved by setting lazy="true" on
the relationship property definition in the CFC.
Example:
In artist.cfc
<cfproperty name="art" fieldtype="one-to-many" cfc="ART" fkcolumn="artistId" lazy="true">
Extra lazy: This applies to one-to-many and many-to-many relationships. This type of lazy loading goes one step
ahead of lazy and does not load all the associated objects when the accessor for that relation is called. It just loads
the primary keys for those objects and keeps a proxy object for them. When you call any method on the wrapper
object, that object's data is loaded from the database.
For example, when you call artist.getarts(), it executes a query on the database to fetch the primary key of the
related artwork objects and creates a proxy artwork object. So, you do not load the data for all the artwork objects
in memory. When you access a particular artwork object and invoke any method on it, then it fires another query
to the database to load that particular artwork object. This is achieved by setting lazy="extra" on the relationship
property definition in the CFC.
Example:
In artist.cfc
<cfproperty name="art" fieldtype="one-to-many" cfc="art" fkcolumn="artistId" lazy="extra" >
proxy: This applies to one-to-one and many-to-one relationships. When the owner object is loaded, the related
object is not loaded from the database. ColdFusion only creates a proxy object for the related object and when any
method is invoked on the related object, the data for the proxy object is loaded from the database and populated in
the proxy object.
For example, if the art-artist table relation is lazy, when the art object is loaded, the artists object is not loaded and
when you call art.getartist(), you would only get a proxy object. When you call any method on the proxy
object, query gets executed on the database to load artist object's data. This is achieved by setting lazy="true" on
the relationship property definition in the CFC
Example:
In ART.cfc
589
Important: An entity is loaded only once in the request (in Hibernate session) and there is always only one copy of it
in the request. So, for artwork and artist relationship, which is lazy, if the artist is already loaded, calling
art.getartist() will not create a proxy object and will return the loaded artist object.
Lazy loading can be disabled by setting lazy="false" on the relationship property definition in the CFC.
Choosing an appropriate lazy loading option is very important for the performance of your application. Extra lazy
means more number of trips to the database (each trip to the database is expensive) but less data in memory whereas
no lazy loading means a huge object graph in the memory. So, you need to balance the approach based on the
application need.
Eager fetching
In this strategy, the associated object or collection is fetched together with the owning entity using a single SQL Join
query. This strategy reduces the number of trips to the database and is a good optimization technique when you always
access the associated object immediately after loading the owning entity. You can define this strategy by setting
fetch="join" for the relationship property definition in the CFC.
Batch fetching
This strategy tells Hibernate to optimize the second SQL select in Immediate fetching or lazy fetching to load batch of
objects or collections in a single query. This allows you to load a batch of proxied objects or uninitilized collections
that are referenced in the current request. This is generally useful in nested tree loading. You can specify this using
"batchsize" attribute for CFC or relationship property.
There are two ways you can tune batch fetching:
Batch fetching at CFC level: This allows batch fetching of the proxied objects and is applied to one-to-one and
many-to-one relationship. For example, consider artwork and artist example where there are 25 art instances
loaded in the request (ORM session). Each artwork has a reference to the artist and the relationship is lazy.
Therefore, art objects contain the proxied object for artist. If you now iterate through all the art objects and call
getartist() on each, by default 25 SELECT statements are executed to retrieve the proxied owners, one for each
artist proxy object. This can be batched by specifying the 'batchsize' attribute on the artist CFC:
<cfcomponent table="artist" batchsize="10" ...>
When you call getartist() on the first art object, it batch fetches 10 artist objects that are proxied in the current
request.
So for 25 art objects, this type of batch fetching makes Hibernate execute a maximum of three queries in batches of
10, 10, and 5.
Batch fetching at collections: This allows batch fetching of value collections, one-to-many or many-to-many
relationships that are uninitialized. For example, consider artist-art one-to-many relationship where there are 25
artists loaded and each artist has a lazy collection of artworks. If you now iterate through the artists and call
getarts() on each, by default 25 SELECT statements are executed, one for each artist to load its art objects. This
can be optimized by enabling batch fetching, which is done by specifying "batchsize" on the relationship
property:
Example:
In artist.cfc:
<cfproperty name="art" fieldtype="one-to-many" cfc="art" fkcolumn="artistId" lazy="true"
batchsize="10">
590
One important thing to understand here is that batchsize here does not mean that 10 artworks are loaded at one
time for a artist. It actually means that 10 artwork collections (artworks for 10 artists) are loaded together.
When you call getarts() on the first artist, artworks for 9 other artists are also fetched along with the one that was
asked for.
The value for batchsize attribute should be chosen based on the expected number of proxied objects or
uninitialized collections in the session.
Caching
Caching is extensively used for optimizing database applications and effectively reducing traffic between the database
and the application.
ColdFusion ORM supports two levels of caching:
Session level
Secondary level
591
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="Artist"
maxElementsInMemory="20"
eternal="true"
overflowToDisk="false"
/>
</ehcache>
The default size is 30 MB. Each spool buffer is used only by its cache.
Turning on trace-level logging shows if backup for cache created/updated using action="put" occurs in the
diskstore.
clearOnFlush: Determines if the MemoryStore must be cleared when the cache is flushed. By default, the
MemoryStore is cleared.
diskExpiryThreadIntervalSeconds: The number of seconds between runs of the disk expiry thread. The default
ormsettings.secondarycacheenabled
This setting defines whether the secondary cache would be used by the application. By default, this is set to false.
ormsettings.Cacheprovider
This setting defines the cache provider that needs to be used for secondary cache. This defaults to EHCache. The
other values for this setting are JBossCache, OSCache, SwarmCache and Hashtable. You can also specify the fully
qualified class name of the cache provider.
ormsettings.cacheconfig
This setting defines the configuration file required by the secondary cache provider. For example, EHCache
requires EHCache.xml that defines the configuration settings for the secondary cache. Specify the path to the XML
file in this setting. If this setting is not defined, cache provider uses its default configuration.
592
After you have configured the secondary cache, it is critical to identify the objects in your application that can be
cached because the data cached by secondary cache is shared by all the sessions of an application. Typically, caching
should be enabled for a CFC that represents:
read-only
This strategy is useful for data that is read frequently but never updated. This is the best performing cache strategy.
nonstrict-read-write
This strategy is useful for data that is updated occasionally. Typically, it is very unlikely that two transactions would
update the same object simultaneously.
read-write
This strategy may be appropriate if your data needs to be updated. It carries more overhead than the two preceding
strategies.
Transactional
This strategy provides the support for transactional cache. It can only be used if the cache provider is transaction
aware.
Support for these strategies depend on the cache provider. Not all the cache providers support all the cache strategies.
For more information on these strategies, see:
www.hibernate.org/hib_docs/reference/en/html/performance-cache.html
The secondary cache can cache the following types of data.
cachename: Defines the name of the cache region to be used by the secondary cache provider. If you do not specify
a region name for the component, the entity name of the component is considered as the cache name. In case a
region is not specified in the configuration file, a region is automatically created with the default configuration.
For example:
<cfcomponent persistent="true" schema="APP" table="Artists" cachename="artist"
cacheuse="read-only">
593
cachename: Defines the name of the cache region to be used by the secondary cache provider. If you do not specify
a region name for the association property, the <comoponent_name>.<property_name> is considered as the cache
name. In case a region is not specified in the configuration file, a region is automatically created with the default
configuration.
For example:
<cfproperty name="art" fieldtype="one-to-many" cfc="CArt" fkcolumn="ArtID"
cachename="ArtistArts" cacheuse="read-only">
this.name="Caching_Example">
this.datasource="cfartgallery">
this.ormenabled="true">
this.ormsettings.secondarycacheEnabled=true>
this.ormsettings.cacheProvider= "ehcache">
this.ormsettings.cacheConfig="ehcache.xml">
CArt.cfc
<cfcomponent persistent="true" schema="APP" table="Art">
<cfproperty name="artid" generator="identity" fieldtype="id"/>
<cfproperty name="artname"/>
<cfproperty name="issold"/>
</cfcomponent>
594
Step 3:
<cfscript>
//This will cache the Artist Component and also the association. It wouldn't cache the Art
objects.
artistObj = EntityLoad("CArtists", 3, true);
//This will cache the query.
availableArts = ORMExecuteQuery("from CArt where issold=0", {}, false, {cacheable=true,
cachename="availableArtsCache"});
</cfscript>
This method is used to evict items for the given component name, from the secondary cache. If the primary key is
specified, then the data of the entity with that primary key is evicted. Primary key should be a value in case of simple
primary key or should be a struct in case of composite primary key.
Example:
<cfset ORMEvictEntity("CArtists")>
This method is used to evict all the collection/association data for the given component name and collection name,
from the secondary cache. If the primary key is specified, then, the collection or association data of the entity with the
primary key is evicted.
Example:
<cfset ORMEvictCollection("CArtists", "art")>
Evicts all the association or collection data of collection art belonging to the component CArtists.
<cfset ORMEvictCollection("CArtists", "art", 1)>
Evict the association or collection data of collection art belonging to the component CArtists with primary key 1.
ORMEvictQueries([cachename])
This method is used to evict the data of all the queries from the default query cache. If cache name is specified, then,
the data of all the queries belonging to the cache region with the given cache name are evicted. Example:
<cfset ORMEvictQueries()>
Evicts the data of all the queries from the default query cache.
<cfset ORMEvictQueries("availableArtsCache")>
Evicts the data of all the queries from the cache region with the name availableArtsCache.
595
Edit ehCache.xml (cfroot/lib)to set the properties for user-defined caches as shown in the following example:
<!--- item to put in user-defined cache --->
<cfset currentTime = Now()>
<!--- put item in user-defined cache --->
<cfset timeToLive=createtimespan(0,0,0,30)>
<cfset timeToIdle=createtimespan(0,0,0,30)>
<cfset customCache = "usercache">
<cfset id = "cache1">
<cfset cachePut(id,currentTime,timeToLive,timeToIdle,customCache)>
<!-- list items in the cache --->
List Items in cache:
<cfset cacheIds = cacheGetAllIds(customCache)>
<cfdump var="#cacheIds#"><br>
<!--- print cache data --->
<cfset cachedData = cacheGet(id,customCache)>
<cfoutput>#cachedData#</cfoutput>
<!--- print cache metadata --->
Cache metadata:
<cfset mdata = cacheGetMetadata(id,"object",customCache)>
<cfdump var="#mdata#">
<!--- clear user-defined cache --->
<cfset cacheRemove(ArrayToList(cacheIds),true,customCache)>
The only exception to this is that objects with nativeId generation are inserted immediately when the object is saved.
Note: ColdFusion creates and manages Hibernate sessions only if ormenabled is set to true in application scope.
When the ColdFusion application starts, it builds the Hibernate session factory that is available for the application life
time. This factory is used to create Hibernate sessions that manage the persistent object lifecycle. When the first CRUD
method is called, a Hibernate session gets created and is closed when the request ends or when the
ormclosesessionmethod is called. For details on how ColdFusion works with Hibernate, see the Architecture on
page 537.
596
In multiple data source scenarios supported in ColdFusion 9 Update 1, there are multiple sessions (one for each data
source) in the same request. For all entity functions, the appropriate sessions are used transparently.
ColdFusion exposes a few methods to let CFML developers work with the Hibernate sessions directly. ORM sessionrelated functions also take optional data source argument. If you do not specify a data source, the default data source
specified for ORM is used. The methods are as follows:
ORMGetSession()
Returns the current ORM session. That is, the Hibernate Session associated with the data source specified in the
application. This returns the underlying Hibernate Session that can be used to call the API, which otherwise is not
exposed by ColdFusion.
For information on Session API, see www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html.
ORMCloseSession()
Closes the current ORM session associated with the data source specified in the application.
ORMFlush()
Flushes the current ORM session associated with the data source specified in the application. ORMFlush flushes all the
pending CRUD operations in that request.
ORMClearSession()
ORMClearSession removes all the entities that are loaded or created in the session. This clears the first level cache and
removes the objects that are not yet saved to the database.
ORMGetSessionFactory()
ORMGetSessionFactory returns the underlying Hibernate SessionFactory object. For information on Session API,
see www.hibernate.org/hib_docs/v3/api/org/hibernate/SessionFactory.html
In a persistent CFC
Using an event handler CFC
To enable event handling for an application, define the following setting: ormsettings.eventhandling= true"
By default, this flag is disabled. If you do not specify this flag while the event handler CFC is defined, the flag is
considered as enabled.
597
preLoad(): This method is called before the load operation or before the data is loaded from the database.
preUpdate(Struct oldData): This method is called just before the object is updated. A struct of old data is passed
to this method to know the original state of the entity being updated.
Note: When you call the EntitySave() method on an object that is not loaded using EntityLoad(), it gets updated but
the intercepter call fails. This happens because an empty map is created for the object and there is no previous data
associated with it.
The event handler CFC needs to implement the CFIDE.ORM.IEventHandler interface. This CFC gets the callbacks
from all persistence-related events and handles them accordingly. In this case, a single CFC handles the events for all
the CFCs.
This interface contains the following methods for the event handler CFC:
For application-wide event handler CFC, you need to specify the component name also along with other arguments.
The methods for application-wide event handler are:
preLoad(entity): This method is called before the load operation or before the data is loaded from the database.
preUpdate(entity, Struct oldData): This method is called just before the object is updated. A struct of old
data is passed to this method to know the original state of the entity being updated.
Note: When you call the EntitySave() method on an object that is not loaded using EntityLoad(), it gets updated but
the intercepter call fails. This happens because an empty map is created for the object and there is no previous data
associated with it.
598
Note: If event handlers are defined in both persistent CFC and event handler CFC, the persistent CFC is given the callback
before calling the application wide event handler.
update: Creates the table (if it does not exist) or updates the table (if it exists).
For example,
<cfset this.ormsettings.dbCreate="update">
Certain specific attributes (DDL-only attributes) defined for the tags cfcomponent and cfproperty can be use to
define various attributes for the auto-generated tables and columns. DDL-only attributes are used only for DDL
generation. For details of these attributes, see the table in the section DDL-only attributes in Column on page 549.
Examples
Application.cfc
<cfset
<cfset
<cfset
<cfset
<cfset
this.name = "AG"/>
this.ormenabled=true/>
this.datasource = "ORM_DDL">
this.ormsettings.dbCreate="dropcreate">
this.ormsettings.sqlscript="mysqlscript.sql">
Artists.cfc
<cfcomponent persistent="true" table="Artists">
<cfproperty name="artistid" fieldtype="id" ormtype="integer" length=10>
<cfproperty name="firstname" ormtype="string" length="20" notnull="true">
<cfproperty name="lastname" ormtype="string" length="20" notnull="true">
<cfproperty name="address" ormtype="string" length="50">
<cfproperty name="city" ormtype="string" length="20">
<cfproperty name="state" ormtype="string" length="2">
<cfproperty name="postalcode" ormtype="string" length="10">
<cfproperty name="email" ormtype="string" length="50" unique="true">
<cfproperty name="phone" ormtype="string" length="20">
<cfproperty name="fax" ormtype="string" length="12">
<cfproperty name="thepassword" ormtype="string" length="20">
</cfcomponent>
art.cfc
599
Naming strategy
When you build a database centric application, typically you would follow some database standard and naming
convention. ColdFusion ORM allows you to define this convention at one central place for the application using the
'naming strategy'.
The advantage of using a naming strategy is that you do not need to change the code throughout your application. The
naming strategy specifies how the table and column have to be named for a CFC and its properties.
Naming strategy takes "logical name" for a table or column and returns the actual table or column name that should
be used.
Logical table name: This is the table name specified for the CFC. If it is not specified, the entity name is taken as the
logical table name. If the entity name is also not specified, the unqualified CFC name, for example, Person for
a.b.c.Person, is taken as the logical table name.
Logical column name: This is the column name specified for a CFC property. If it is not specified, the property
name is taken as the logical column name.
Naming strategy is applied to an application by setting the following in Application.cfc
<cfset this.ormsettings.namingstrategy="strategy">
default: This strategy uses the logical table or column name as it is. ColdFusion ORM using this value as the
default strategy.
smart: This strategy changes the logical table or column name to uppercase. Also, if the logical table or column
name is in camel case, this strategy breaks the camelcased name and separates the broken words using underscore.
For example, for a CFC named "OrderProduct", this strategy changes the table name as "ORDER_PRODUCT".
your own cfc : You can get complete control of the naming strategy by providing your own implementation. You
need to specify the fully qualified name of the CFC as the value for naming strategy. This CFC must implement
cfide.orm.INamingStrategy interface.
600
/**
* Strategy to specify the table name for a CFC and column name for a property in the cfc.
* This can be used to specify the application specific table and column naming convention.
* This rule will be applied even if the user has specified the table/column name in the mapping
so that
* the name can be changed for any application at one place without changing the names in all the
code.
*/
interface
{
/**
* Defines the table name to be used for a specified table name. The specified table name is either
* the table name specified in the mapping or chosen using the entity name.
*/
public string function getTableName(string tableName);
/**
* Defines the column name to be used for a specified column name. The specified column name is
either
* the column name specified in the mapping or chosen using the proeprty name.
*/
public string function getColumnName(string columnName);
}
Note: The naming strategy applies to all the table or column names, which you use in the mapping including link table
and fkcolumn, even though there is no CFC or cfproperty associated with them.
601
Introduction
You can use multiple data sources for ORM in ColdFusion applications. A multiple data source setup is useful in
scenarios where your application has multiple modules that interact with each other.
Hibernate inherently supports single data source for a Hibernate configuration. To support multiple data sources,
ColdFusion builds and manages multiple Hibernate configurations and SessionFactory objects, one for each data
source in the application.
Usage scenario
Consider an application with the following three modules:
HR
Finance
Sales
Assume that all these modules have their own databases (and therefore separate data sources). But at the applicationlevel, all the three modules have to interact with each other. A single data source makes it impossible to build the entire
application using ORM. Building three separate applications is not advisable as the interaction between the
applications is possible only using web services.
If you use a multiple data source setup for ORM, all the three modules can be built in ORM. They can be part of the
same application and the modules can interact with each other.
Author.cfc
<cfcomponent persistent="true" datasource="bookclub" table="author">
</cfcomponent>
602
ORM settings
The following are the data source-specific ORM settings for which you can specify string or struct values in the
Application.cfc:
schema
catalog
dialect
dbcreate
sqlscript
For multiple data sources, a struct can be specified with data source name as the key and the appropriate setting as the
value. If a string value is specified, it applies to the default data source of ORM.
Example 1
<cfset this.ormsettings.dbcreate={artgallery="dropcreate", bookclub="none"}>
Example 2
<cfset this.ormsettings.dbcreate="dropcreate">
If multiple data sources are used for ORM, these settings apply to the default ORM data source.
artists.cfc
<cfcomponent persistent="true" table="artists" datasource="cfartgallery">
<cfproperty name="ArtistID" fieldtype="id">
<cfproperty name="FirstName">
<cfproperty name="LastName">
<cfproperty name="art" fieldtype="one-to-many" cfc="art" fkcolumn="ArtistID">
</cfcomponent>
authors.cfc
<cfcomponent persistent="true" table=authors datasource="cfbookclub">
<cfproperty name="AuthorID" fieldtype="id">
<cfproperty name="LastName">
<cfproperty name="FirstName">
</cfcomponent>
603
index.cfm
<cfoutput>Original Data<br></cfoutput>
<cfset artistObj = EntityLoad("artists", 1, true)>
<cfoutput>#artistObj.getArtistID()# | #artistObj.getFirstName()# |
#artistObj.getLastName()#<br></cfoutput>
<cfset artObj = artistObj.getart()>
<cfoutput>#artObj[1].getartname()# <br></cfoutput>
<cfset authorObj = EntityLoad("authors", 1, true)>
<cfoutput>#authorObj.getFirstName()#</cfoutput>
<cfoutput>#authorObj.getLastName()#</cfoutput>
ORMGetSession
Description
Returns the Hibernate session associated with the data source in the request. If ORM is not configured for this data
source, it results in an exception. If data source is not specified, the Hibernate session of the default data source is
returned.
Use this session object to call the APIs, which, otherwise, ColdFusion does not expose.
For information on session APIs, see:
http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/Session.html
Function syntax
ormgetsession([datasource])
ORMCloseSession
Description
Closes the Hibernate session associated with the data source in the request. If you do not specify a data source, the
Hibernate session associated with the default data source is closed.
Function syntax
ormclosesession([datasource])
ORMCloseAllSessions
Description
Closes all Hibernate sessions in the request.
Function Syntax
ormcloseallsessions()
History
ColdFusion 9 Update 1: Added this function
604
ORMFlush
Description
Flushes the Hibernate session associated with the data source in the request. ORMFlush flushes all pending CRUD
operations in the request. Any changes made in the objects, in the current ORM session, are saved to the database.
If you do not specify the data source, the Hibernate session associated with the default data source is flushed.
Function syntax
ormflush([datasource])
ORMFlushall
Description
Flushes all the current Hibernate sessions in the request.
Function syntax
ormflushall()
History
ColdFusion 9 Update 1: Added this function
ORMClearSession
Description
Clears the Hibernate session associated with the given data source.
The function clears the first level cache and removes the objects that are not yet saved to the database.
If you do not specify the data source, the Hibernate session associated with the default data source is cleared.
Function syntax
Ormclearsession([datasource])
ORMGetSessionFactory
Description
Returns the Hibernate Session Factory object associated with the data source. Results in an error if ORM is not
configured for this data source. If you do not specify the data source, the Hibernate session factory object associated
with the default data source is returned.
For information on Session API, go to the following URL:
http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/SessionFactory.html
Function syntax
Ormgetsessionfactory([datasource])
605
ORMEvictQueries
Description
This method is used to evict the data of all the queries from the default query cache of the specified data source. If cache
name is specified, then the data of all queries belonging to the cache region with the given cache name are evicted.
If no data source is specified, the default query cache of the default data source is evicted.
Syntax
ORMEvictQueries([cachename])
ORMEvictQueries([cachename], datasource)
Parameter
Description
cachename
datasource
Name of the data source whose cache you want to evict. If you do not specify the cache, the default query cache is
evicted.
ORMExecuteQuery
Description
Executes a Hibernate Query Language (HQL) query.
By default, this function works on ORM's default data source. To use this function for another data source, specify the
data source key-value pair within the queryoptions.
Syntax
ORMExecuteQuery(hql, [params] [,unique])
ORMExecuteQuery(hql, [,unique] [, queryoptions])
ORMExecuteQuery(hql, params [,unique] [,queryOptions])
Parameters
Parameter
Description
Hql
Params
Unique
Queryoptions
Example
<cfset artistArr = ORMExecuteQuery("from Artists where artistid=1", true,
{datasource="cfartgallery"})>
<cfset countArray = ORMExecuteQuery("select count(*) from Authors", [], false,
{datasource="cfbookclub"})>
606
607
The following is a simplified representation of the relationship between Flash and ColdFusion:
SWF files
.SWFs
Computer
Interactive TV
Mobile phone
PDA
HTTP
Application Server
Flash Remoting
Web
services
Database
Planning your SWF application
When you are planning ColdFusion application development with Flash UIs, remember the importance of separating
display code from business logic. Separating display code from business logic enables your ColdFusion applications to
interact with multiple client types, such as SWF applications, web browsers, and web services.
When you build ColdFusion applications for multiple clients, your ColdFusion pages and components return
common data types, including strings, integers, query objects, structures, and arrays. Clients that receive the results
can process the passed data according to the client type, such as ActionScript with Flash, or CFML with ColdFusion.
608
To use the Flash Remoting service with ColdFusion, you build ColdFusion pages and components or deploy Java
objects. In ColdFusion pages, you use the Flash variable scope to interact with SWF applications. ColdFusion
components (CFCs) natively support Flash interaction. The public methods of Java objects are also available to the
Flash Remoting service.
The Flash Remoting ActionScript API has been updated to comply with ActionScript 2.0. The ActionScript 2.0 version
of the API consists of the following significant features:
Flash Remoting MX 2004 ActionScript 2.0 API Features
Enforcement of strict data typing, which requires you to declare the data types of variables and prohibits you from assigning different types
of data to them.
Enforcement of case sensitivity, which means that myvar and myVar are two different variables, though they were considered the same
variable with different spellings in ActionScript 1.0.
A new Service class, which lets you create a gateway connection and at the same time obtain a reference to a service and its methods. It
includes the connection property, which returns the connection and also lets you set credentials for authorization on the remote server.
Note: The NetServices class is still supported but has been deprecated in favor of the new Service and Connection classes
A new Connection class that helps you create and use Flash Remoting connections.
Note: The Connection class supersedes the former NetConnection class.
A new PendingCall object returned on each call to a service method that is run using the Service object. The PendingCall object contains the
responder property, which you use to specify the methods to handle the results of the service call.
A new RelayResponder class, which specifies the methods to which the result and fault outcomes of a service call are relayed.
A RecordSet object that contains new properties (columnNames, items, and length), new methods (clear(), contains(),
editField(), getEditingData(), getIterator(), getLocalLength(), getRemoteLength(), isEmpty(), and sortItems()),
and the new modelChanged event.
For more information on the ActionScript 2.0 Flash Remoting API, see Flash Remoting ActionScript Dictionary Help.
Both the web.xml file and the gateway-config.xml file are located in the WEB-INF directory of your ColdFusion server.
As a general rule, you do not have to change these web.xml settings.
609
ColdFusion MX 7 and later versions of ColdFusion configure Flash gateways differently from previous ColdFusion
releases. Parameters that worked before this release are no longer supported, and you specify all configuration
parameters in the gateway-config.xml file. Also, the Flash gateway now supports a whitelist, which specifies which
remote sources can be accessed through the gateway. The two web.xml entries that identify the whitelist must specify
your gateway-config.xml file and gateway-config as the parent node.
You can modify the gateway-config.xml file to configure service adapters, add service names to the whitelist, change
the logging level, and specify how the gateway handles case sensitivity.
You can configure gateway features in the gateway-config.xml file as follows:
610
Feature
Description
service adapters
security
You can edit security settings in child tags of the <security> tag.
In the <login-command> tag, you can set the
flashgateway.security.LoginCommand implementation for performing local
authentication on a specific application server. By default, the <login-command> tag is
set to the following values:
<login-command>
<class>flashgateway.security.JRunLoginCommand</class>
<server-match>JRun</server-match>
</login-command>
In the <show-stacktraces> tag, you can enable stack traces. Stack traces are useful
for debugging and product support, but they should not be sent to the client in
production mode because they can expose internal information about the system. The
following <show-stacktraces> tag is the default tag:
<show-stacktraces>false</show-stacktraces>
The <whitelist> tag specifies which remote sources can be accessed through the
gateway. The * character can be used as a wildcard to imply ALL matches. The following
<whitelist> tag shows the default value:
<whitelist>
<source>*</source>
</whitelist>
When you deploy your application, ensure that you change this setting so that it
specifies only the services that the gateway needs to access to run your application.
Remember that for ColdFusion based services, directories are treated as "packages" and
thus you specify a period delimited path from the web root to the directory or file
containing the services you will allow access to. An asterisk wildcard allows access to all
services in a particular directory. You can have multiple <source> tags.
The following whitelist allows access to the webroot/cfdocs/exampleapps/ directory,
which includes the flash1 through flash5 Flash Remoting example directories. It also
allows access to a webroot/BigApp/remoting directory and its children.
<whitelist>
<source>cfdocs.exampleapps.*</source>
<source>BigApp.remoting.*</source>
</whitelist>
611
Feature
Description
logger level
You can set the level of logging between None, Error, Info, Warning, and Debug. The
following tag is the default logger level tag:
<logger level="Error">coldfusion.flash.ColdFusionLogger</logger>
redirect URL
In the <redirect-url> tag, you can specify a URL to receive HTTP requests that are
not sent with AMF data. By default, the <redirect-url> tag is set to
{context.root}, which is the context root of the web application:
<redirect-url>{context.root}</redirect-url>
case sensitivity
The <lowercase-keys> tag specifies how the gateway handles case sensitivity.
ActionScript 1.0 and ColdFusion use case insensitive data structures to store associative
arrays, objects and structs. The Java representation of these data types requires a caseinsensitive Map, which the gateway achieves by forcing all keys to lowercase.
ActionScript 2.0 is case sensitive and requires a <lowercase-keys> tag value of false.
The following <lowercase-keys> tag is the default tag:
<lowercase-keys>true</lowercase-keys>
Description
Flash.Params
Array that contains the parameters passed from the SWF application. See Accessing parameters passed from
If you do not pass any parameters, Flash.params still exists, but it is Flash on page 612.
empty.
Flash.Result
Flash.Pagesize
The number of records returned in each increment of a record set to a See Returning records in increments to
Flash on page 614.
SWF application.
The following table compares the ColdFusion data types and their ActionScript equivalents:
ActionScript data type
Number
Boolean (0 or 1)
String
612
ActionScript Object
Structure
Null
Undefined
Ordered array
Array
Struct
Date object
Date
XML object
XML document
RecordSet
Query object (when returned to a SWF application only; you cannot pass a
RecordSet from a SWF application to a ColdFusion application)
If a string data type on the server represents a valid number in ActionScript, Flash can automatically cast it to a
number if needed.
To return multiple, independent values to the SWF application, place them in a complex variable that converts to
a Flash Object, Array, or Associative Array, that can hold all of the required data. Return the single variable and
access its elements in the SWF application.
For a complete explanation of using Flash Remoting data in ActionScript, see Using Flash Remoting MX 2004Help.
613
Collection
ActionScript example
Notes
Strict array
Mixed array
<cfset p1=Flash.Params[1][1]>
<cfset p2=Flash.Params[1][2]>
myStruct["one"] = "orange";
myService.myMethod(myStruct);
<cfset p1=Flash.Params[1].zero>
<cfset p2=Flash.Params[1].one>
Using an ActionScript myService.myMethod({ x:1, Y:2, z:3 }); This notation provides a convenient way of passing named
object initializer for
arguments to ColdFusion pages. You can access these
named arguments
arguments in ColdFusion pages as members of the Flash scope:
<cfset p1 = Flash.x>
<cfset p2 = Flash.y>
<cfset p3 = Flash.z>
The Flash.Params array retains the order of the parameters as they were passed to the method. You use standard
structure name syntax to reference the parameters; for example:
<cfquery name="flashQuery" datasource="cfdocexamples">
SELECT ItemName, ItemDescription, ItemCost
FROM tblItems
WHERE ItemName EQ '#Flash.paramName#'
</cfquery>
In this example, the query results are filtered by the value of Flash.paramName, whichreferences the first parameter
in the passed array. If the parameters are passed as an ordered array from the SWF application, you use standard
structure name syntax; for example:
<cfset Flash.Result = "Variable 1:#Flash.Params[1]#, Variable 2: #Flash.Params[2]#">
Note: ActionScript array indexes start at zero. ColdFusion array indexes start at one.
614
In the example, two string variables are added to a structure; one with a formatted date and one with a simple
message. The structure is passed back to the SWF application using the Flash.Result variable.
<cfset Flash.Result = tempStruct>
Remember, the directory name is the service address. The helloWorld.cfm file is a method of the helloExamples Flash
Remoting service. The following ActionScript example calls the helloWorld ColdFusion page and displays the values
that it returns:
import mx.remoting.*;
import mx.services.Log;
import mx.rpc.*;
// Connect to helloExamples service and create the howdyService service object
var howdyService:Service = new Service(
"http://localhost/flashservices/gateway",
null,
"helloExamples",
null,
null );
// Call the service helloWorld() method
var pc:PendingCall = howdyService.helloWorld();
// Tell the service what methods handle result and fault conditions
pc.responder = new RelayResponder( this, "helloWorld_Result", "helloWorld_Fault" );
function helloWorld_Result(re:ResultEvent)
{
// Display successful result
messageDisplay.text = re.result.HELLOMESSAGE;
timeDisplay.text = re.result.TIMEVAR;
}
function helloWorld_Fault(fe:FaultEvent)
{
// Display fault returned from service
messageDisplay.text = fe.fault;
}
Note: Due to ActionScript's automatic type conversion, do not return a Boolean literal to Flash from ColdFusion. Return
1 to indicate true, and return 0 to indicate false.
615
In this example, if a single parameter is passed from the SWF application, the pagesize variable is set to the value
of the Flash.Params[1] variable; otherwise, the value of the variable is the default, 10. Next, a statement queries
the database. After the querying, the pagesize variable is assigned to the Flash.Pagesize variable. Finally, the
query results are assigned to the Flash.Result variable, which is returned to the SWF application.
3 Save the file.
When you assign a value to the Flash.Pagesize variable, you are specifying that if the record set has more than a
certain number of records, the record set becomes pageable and returns the number of records specified in the
Flash.Pagesize variable. For example, the following code calls the getData() function of the CFMService and uses
the first parameter to request a page size of 5:
import mx.remoting.*;
import mx.services.Log;
import mx.rpc.*;
// Connect to helloExamples service and create the CFMService service object
var CFMService:Service = new Service(
"http://localhost/flashservices/gateway",
null,
"helloExamples",
null,
null );
// Call the service getData() method
var pc:PendingCall = CFMService.getData(5);
// Tell the service what methods handle result and fault conditions
pc.responder = new RelayResponder( this, "getData_Result", "getData_Fault" );
function getData_Result(re:ResultEvent)
{
// Display successful result
DataGlue.bindFormatStrings(employeeData, re.result, "#PARKNAME#, #CITY#, #STATE#");
}
function getData_Fault(fe:FaultEvent)
{
// Display fault returned from service
trace("Error description from server: " + fe.fault.description);
}
In this example, employeeData is a Flash list box. The result handler, getData_Result, displays the columns
PARKNAME, CITY, and STATE in the employeeData list box. After the initial delivery of records, the RecordSet
ActionScript class assumes the task of fetching records. In this case, the list box requests more records as the user
scrolls the list box.
You can configure the client-side RecordSet object to fetch records in various ways using the
RecordSet.setDeliveryMode ActionScript function.
616
In this example, the helloWorld function is created. The cfreturn tag returns the result to the SWF application.
3 Save the file.
The helloWorld service function is now available through the flashComponent service to ActionScript. The
following ActionScript example calls this function:
617
import mx.remoting.*;
import mx.services.Log;
import mx.rpc.*;
// Connect to the Flash component service and create service object
var CFCService:Service = new Service(
"http://localhost/flashservices/gateway",
null,
"helloExamples.flashComponent",
null,
null );
// Call the service helloWorld() method
var pc:PendingCall = CFCService.helloWorld();
// Tell the service what methods handle result and fault conditions
pc.responder = new RelayResponder( this, "helloWorld_Result", "helloWorld_Fault" );
function helloWorld_Result(re:ResultEvent)
{
// Display successful result
messageDisplay.text = re.result.HELLOMESSAGE;
timeDisplay.text = re.result.TIMEVAR;
}
function helloWorld_Fault(fe:FaultEvent)
{
// Display fault returned from service
messageDisplay.text = fe.fault;
}
In this example, the CFCService object references the flashComponent component in the helloExamples directory.
Calling the helloWorld function in this example executes the function that is defined in flashComponent.
For ColdFusion components, the component filename, including the directory structure from the web root, serves as
the service name. Remember to delimit the path directories with periods rather than backslashes.
When you place your Java files in the classpath, the public methods of the class instance are available to your SWF
movie.
For example, assume the Java class utils.UIComponents exists in a directory in your ColdFusion classpath. The Java
file contains the following code:
618
package utils;
public class UIComponents
{
public UIComponents()
{
}
public String sayHello()
{
return "Hello";
}
}
Note: You cannot call constructors with Flash Remoting. Use the default constructor.
In ActionScript, the following javaService call runs the sayHello public method of the utils.UIComponents class:
import mx.remoting.*;
import mx.services.Log;
import mx.rpc.*;
// Connect to service and create service object
var javaService:Service = new Service(
"http://localhost/flashservices/gateway",
null,
utils.UIComponents",
null,
null );
// Call the service sayHello() method
var pc:PendingCall = javaService.sayHello();
// Tell the service what methods handle result and fault conditions
pc.responder = new RelayResponder( this, "sayHello_Result", "sayHello_Fault" );
function sayHello_Result(re:ResultEvent)
{
// Display successful result
trace("Result is: " + re.result);
}
function sayHello_Fault(fe:FaultEvent)
{
// Display fault returned from service
trace("Error is: " + fe.fault.description);
}
Note: For more information about using Java objects with ColdFusion, see Using Java objects on page 1135
619
The second cfset tag in this example fails because it tries to divide by zero (0). The message attribute of the cfthrow
tag describes the error; ColdFusion returns this attribute to the SWF application.
To handle the error in your SWF application, create a fault handler like causeError_Fault in the following example:
import mx.remoting.*;
import mx.services.Log;
import mx.rpc.*;
// Connect to service and create service object
var CFMService:Service = new Service(
"http://localhost/flashservices/gateway",
null,
"helloExamples",
null,
null );
// Call the service causeError() method
var pc:PendingCall = CFMService.causeError();
// Tell the service what methods handle result and fault conditions
pc.responder = new RelayResponder( this, "causeError_Result", "causeError_Fault" );
function causeError_Result(re:ResultEvent)
{
// Display successful result
messageDisplay.text = re.result;
}
function causeError_Fault(fe:FaultEvent)
{
// Display fault returned from service
trace("Error message from causeError is: " + fe.fault.description);
}
This example displays the trace message from the causeError_Fault function in the Flash Output panel. The portion
of the message that is contained in fe.fault.description is the portion of the message that is contained in
#cfcatch.message# in the causeError.cfm page.
Note: When you create a ColdFusion page that communicates with Flash, ensure that the ColdFusion page works before
using it with Flash.
620
Note: With ColdFusion 9, you will need to install LiveCycle Data Services 2.6.1 manually because it is not available
as an option with the ColdFusion installer. However, ColdFusion 9 is available with the BLAZE DS installation, which
allows messaging support. For more information about manually installing LiveCycle Data Services ES 2.6.1, see
Installing LiveCycle Data Services Manually in the Installation Guide.
application server where the page is viewed. Do not select to compile code that you deploy on the server; this option
is for development purposes only.
4 Click Next and complete creating the project, then click Finish.
If you select Basic on the first Create a Flex Project page, and decide later to compile the application for use with
ColdFusion, configure Flex Builder manually, as follows:
1 Select Project > Properties.
2 Select Flex Complier in the right pane of the Properties dialog.
3 In the Additional Compiler arguments add -services= followed by the absolute path to the services-config.xml
file in the local ColdFusion installation. For example, on a Windows system with a default ColdFusion stand-alone
installation, specify the following argument string.
-services=C:/ColdFusion9/wwwroot/WEB-INF/flex/services-config.xml
621
Data services in step 3, you can select to compile the application locally or on the server. Select to compile on the
server only when you are developing your application, for convenience. Do not select to compile on the server code
that you deploy, because the MXML page is not compiled to a SWF file until the user requests it, and the compiler
does not create an HTML wrapper page.
5 Click Finish to complete the configuration.
If you do not specify ColdFusion in the Server technology section of the Create a Flex project page, and decide later to
compile the application for use with ColdFusion, configure Flex Builder manually, as follows:
1 Select Project > Properties.
2 Select Flex Complier in the right pane of the Properties dialog.
3 In the Additional Compiler arguments add -services= followed by the absolute path to the services-config.xml
file in the local ColdFusion installation. For example, on a Windows system with a default ColdFusion stand-alone
installation, specify the following argument string.
-services=C:/ColdFusion8/wwwroot/WEB-INF/flex/services-config.xml
Specify a CFC
To specify a CFC to connect to, you do one of the following:
Specify the dot-delimited path from the web root to the CFC in the MXML.
Create a named resource for the CFC. Creating this resource is like registering a data source; you then use the
resource name in your XML.
ColdFusion 9 supports BlazeDS that allows messaging support for ColdFusion. When you install ColdFusion, the
following files are added to the /WEB-INF/flex directory:
remoting-config.xml
messaging-config.xml
services-config.xml
proxy-config.xml
The destination ColdFusion is preconfigured in remoting-config.xml. The default source value for this destination is
the wildcard, *. For more information about the changes in Flash Remoting for ColdFusion 9, see Changes in the XML
configuration files for Flash Remoting in ColdFusion 9 and ColdFusion 9.0.1.
622
You do not have to use the ColdFusion destination if you have configured other valid destinations in the configuration
file. In this case, the destination definition must specify * as the value of its source element. If you specify a source
other than * in remoting-config.xml, then that source definition overrides the source specified in the MXML.
For details of defining a destination, see Create a named resource for a CFC.
The source attribute specifies the dot notation to the CFC from the web root (the classpath to the CFC).
The channel-ref tag refers to the channel-definition in the services-config.xml file. In the preceding sample, the mycfamf channel-definition has been referenced, which looks similar to the following:
623
Description
destination id
The destination attribute that the MXML mx:RemoteObject tag must specify to access the
CFC.
channels
A container for one of more child channel attributes specifying the AMF channels to use to
access the ColdFusion server.
channel-ref
source
The dot-delimited file path to the CFC, from the cfWebRoot, or, if the use-mappings property is
true, an entry in the ColdFusion Administrator Mappings page.
access
Properties that control how the CFC is accessed on the ColdFusion server.
Description
channel-definition id
Channel definition
coldfusion
Contains tags to set access levels, mappings to find CFCs, access to public or remote methods.
access
define the resolution rules and access level of the CFC being invoked
use-mappings
Use the ColdFusion mappings to find CFCs, by default only CFC files under your web root can be
found.
method-access-level
624
Elements
Description
use-accessors
Whether the Value Object CFC has getters and setters. Set the value of use-accessors to true if
there are getters and setters in the Value Object CFC.
use-structs
Set the value of use-structs to true if you don't require any translation of ActionScript to CFCs. The
assembler can still return structures to Flex, even if the value is false. The default value is false.
force-cfc-lowercase
force-query-lowercase
force-struct-lowercase
Whether to make property names, query column names, and structure keys lowercase when
converting to ActionScript. Query column names must precisely match the case of the
corresponding ActionScript variables. The default value is false.
If you did not create a destination for the CFC, specify the ColdFusion destination and the CFC path in the
mx:RemoteObbject tag; for example:
<mx:RemotObject
id="myCfc"
destination="ColdFusion"
source="myApplication.components.User"/>
In this example, when a user presses a button, the Click event calls the CFC method getUsers.
4 Specify a handler for the returned result of the CFC method call for the <mx:RemoteObject> tag, as the following
example shows.
private function my_CFC_handler( event:ResultEvent )
{
// Show alert with the value that is returned from the CFC.
mx.controls.Alert.show(ObjectUtil.toString(event.result));
}
625
You can also use a traditional non-ORM CFC. In this case, the Fetch and Sync Methods use the cfquery tag and
related tags and function for database operations.
626
To manage interactions with the AIR application and keep the data synchronized, ColdFusion application uses a
component called the SyncManager. The SyncManager implements the CFIDE.AIR.ISyncManager interface. The
component has two functions:
A fetch function that the AIR application calls to get data from ColdFusion. This function is not part of the
ISyncManager interface, but is required. The function can have any arbitrary name, but is called fetch by
convention.
A sync function that the AIR application calls to synchronize the ColdFusion and AIR data sources when the
application updates or changes data. This function takes three parameters:
operations An array of operations to perform INSERT, UPDATE, or DELETE.
clientObjects An array of objects, where each item in the array represents the client's current view of the data
to be synchronized.
originalObjects An array of objects, each item in this Array represents the corresponding original data from the
server (if any), such as an existing employee record that a user is updating. For an INSERT operation, this object is
null. For a DELETE operation, this object is normally the same as the current data.
Incase of Conflict during Sync process, the sync function returns to the AIR client an Array of
"CFIDE.AIR.Conflict.cfc" objects. Each of this Conflict object consists of a single serverObject element. The sync
function sets the element to equal the server copy of the record that is in conflict. The client application can then handle
the conflict as described in Conflict management on page 635.
Server-Side notes
When the sync function performs a DELETE operation, it gets the primary key ID from the OriginalObject of the
Sync method, as the ClientObject is NULL. For update and insert operations, use the ClientObject key value.
When you do an INSERT operation, the CFC checks whether the OriginalObject parameter of the sync method is
a simple value, as in the following code:
{NOT IsSimpleValue(OriginalObject)}
In an INSERT operation, OriginalObject passed to the Sync function is null. So if you attempt to retrieve any of its
properties, you get a Method NOT Found error. For Example, OriginalObject.GetID results in a Method GetID()
not found error. So, for Insert operation, use ClientObject to access various fields.
While a ColdFusion application can use cfquery to directly manage the database, most AIR applications are
expected to use the ORM feature. The discussion here uses ColdFusion ORM for server-side data management.
You may see the following kind of error message if you are using ColdFusion 8 Remoting with AIR offline
applications, which have server side "Sync" method using ORM EntitySave()/EntityDelete() methods.
Error handling message: flex.messaging.MessageException: Unable to invoke CFC - a different
object with the same identifier value was already associated with the session: [address#1].
Root cause:org.hibernate.NonUniqueObjectException: a different object with the same
identifier value was already associated with the session: [address#1]
You may also encounter this error with ColdFusion 9 Remoting but only for EntityDelete method.
To resolve this sort of error, call your EntitySave/EntityDelete method in following way in "Sync" method.
<cfif operation eq "INSERT" OR operation eq "UPDATE">
<cfset obj = ORMGetSession().merge(clientobject)>
<cfset EntitySave(obj)>
<cfelseif operation eq "DELETE">
<cfset obj = ORMGetSession().merge(originalobject)>
<cfset EntityDelete(obj)>
</cfif>
627
In case of a conflict, the sync function returns an array of "CFIDE.AIR.Conflict" objects to the client. There are
four properties a conflict object can have: operation,serverobject,clientobject,originalobject.
The serverobject property of the conflict object must be a user-defined CFC type that represents the server-side
database table. The following example generates a conflict object with a valid ServerObject property of type
employee.cfc, which represents the Employee table:
<cfset serverobject = EntityLoadByPK("employee",originalobject.getId())>
<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>
<cfset conflict.serverobject = serverobject>
<cfset conflict.clientobject = clientobject>
<cfset conflict.originalobject = originalobject>
<cfset conflict.operation = operation>
<cfset conflicts[conflictcount++] = conflict>
<cfreturn conflicts>
If you are using ColdFusion ORM, you can replace the preceding example with the following code.
<cfset conflict = CreateObject("component","CFIDE.AIR.Conflict")
<cfset serverobject = EntityLoadByPK("employee",#res.IDENTITYCOL#)>
<cfset conflict.SetServerobject(serverobject)>
When an AIR client with stale data tries to update an already deleted record from the database, server throws the
conflict, and the client's conflict handle, which has the KeepAllServerObjects or KeepServerObject method
accepts the changes from the server. However, the client method does not delete the stale record, which no longer
exists in the server database, from the client database.
To prevent this issue: The serverObject property of the conflict object returned by the server must be null, if the
record that the client requests for updating is no longer in the database. For example:
<cfset serverobject = EntityLoadByPK("employee",originalobject.getId())>
<!----If the operation is INSERT, serverObject is also NULL.hence NEQ condition---->
<cfif not isdefined('serverobject') and operation NEQ "INSERT" >
<cflog text="CONFLICT::SERVER OBJECT NOT FOUND, RECORD MAY BE DELETED ALREADY">
<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>
<cfset conflict.clientobject = clientobject>
<cfset conflict.originalobject = originalobject>
<cfset conflict.operation = operation>
<cfset conflicts[conflictcount++] = conflict>
<cfcontinue>
</cfif>
Data object
The AIR application represents the managed data in an ActionScript object that corresponds to the ColdFusion-side
data CFC. For example, in the Employee example, the AIR application has an Employee.as file containing an Employee
ActionScript class that corresponds to ColdFusion employee.cfc:
628
package test.basic
{
[Bindable]
[RemoteClass(alias="AIRIntegration.employee")]
[Entity]
public class Employee
{
/** The user id of the employee **/
[Id]
public var id:int;
public var firstName : String;
public var lastName : String;
public var displayName : String;
....
public var countryCode : String = 'US';
....
}
Note: You do not need to create any SQLite databases or tables; they are created automatically. For example, once the
Employee class is defined as above, the first time you invoke the class, the equivalent SQLite table is created for server data
persistence.
Purpose
[Entity]
Specifies that instances of this class can be persisted to the SQLite database. This element is
required.
[Table(name="tableName")]
The name of the SQLite table in which the object is to be stored. Defaults to the name of the
class.
[Id]
Precedes a field definition. Indicates that the field is a primary key in the table. For composite
keys, use Id tags on all the primary key fields.
[Transient]
A Boolean value specifying whether the property or field is persistent. A True value indicates
that the field is not persistent and so it is not a part of the client side Sqlite table.
[Column(name="name",
columnDefinition="TEXT|INTEGER|
FLOAT|BOOLEAN|VARCHACHAR",
nullable=true|false, unique=true|false)]),
Specifies the SQLite database column that contains data for this field.
name: Column name. If not specified, defaults to the property name.
columnDefinition: The SQL Datatype to use for the column.
nullable: Specifies whether a field can have a null value.
unique: Specifies whether the value for each field must be unique within the column.
[RemoteClass]
Used for all remote objects, not just ColdFusion. The alias attribute identifies the
corresponding class on the remote server. This information is used to map between
ActionScript data types and the remote data types.
It is mandatory that you specify the [RemoteClass] metadata tag for the ActionScript classes
or entities that map with the server-side CFC. If you do not specify this metadata tag, you get
a runtime error. For example, you specify the alias name for the Address entity as follows:
[RemoteClass(alias="myFolder.AIRIntegration.Address")]
The alias name must be unique within the AIR application.
Note: For private properties in a class, set [Column] metadata on the accessor functions (getxxx and setxxx) and not on
the private property, as shown in the following code:
629
Client Side
ColdFusion 9 extends offline application support to the client side of the application by letting you code ActionScript
elements on the client side. The data that is exchanged and synchronized on the client side is managed through
persistent objects in the local or offline database.
Managing relationships
The ActionScript persistent framework lets you define the following relationship types between two persistent objects.
one-to-one
one-to-many
many-to-one
many-to-many
To understand how the persistent framework handles relationships, let us consider an example of the Employee and
Department objects in a database.
If you do not specify attribute values, the default values are taken as follows:
The default value for targetEntity is the ActionScript type of the referring field.
Note: In case you are using ORM CFCs, the remotingFetch attribute in the <cfproperty> tag is set to false by default for
all relationships. You must set this attribute to true to retrieve data on the client side.
One-to-one relationship
Consider a one-to-one relationship where one employee belongs to a single department. You can use code like the
following to define a one-to-one mapping between the Department and Employee objects with DEPTID as the foreign
key column name.
[Entity]
[Table(name="employee")]
public class Employee
{
[Id]
var id:uint;
[OneToOne(targetEntity="Department"|fetchType="EAGER(default)|LAZY")]
[JoinColumn(name="DEPTID", referencedColumnName="DEPT_ID")]
var dept:Department;
}
630
The [JoinColumn]tag specifies the foreign key column and all the attributes of the column tag. Do not specify
[JoinColumn] for both the entities in the relationship. For example, in the one-to-one relationship between the
Department and Employee objects, specify [JoinColumn]only for one of the entities depending on the direction of
the relationship.
referencedColumnName specifies the primary key column that it refers to. Class indicates the target entity, which is
Department in this example.
The default fetchType value is EAGER. See Lazy loading and fetch type on page 631 for information on fetch types.
One-to-many relationship
Consider a one-to-many relationship where one employee belongs to many departments. You can use code like the
following to define a one-to-many mapping between the Department and Employee objects.
public class Employee
{
[Id]
var id:uint;
[OneToMany(targetEntity="Department",mappedBy="department",
fetchType="EAGER|LAZY(default)")]
var depts:ArrayCollection;
}
There is no column specified in the Employee table but refers to the field in the Department entity that points to the
Employee entity.
The default fetchType value is LAZY. See Lazy loading and fetch type on page 631 for information on fetch types
Many-to-one relationship
Consider a many-to-one relationship where many employees belong to a single department. You can use code like the
following to define a many-to-one mapping between the Department and Employee objects.
public class Employee
{
[Id]
var id:uint;
[ManyToOne(targetEntity="Department",fetchType="EAGER(default)|LAZY")]
[JoinColumn(name="deptId",referencedColumnName="DEPT_ID")]
var dept:Department;
}
The default fetchType value is EAGER. See Lazy loading and fetch type on page 631 for information on fetch types
Many-to-many relationship
Consider a many-to-many relationship where many employees belong to many departments. You can use code like
the following to define a many-to-many mapping between the Department and Employee objects.
631
The default fetchType value is LAZY. See Lazy loading and fetch type on page 631 for information on fetch types.
For a many-to-many relationship, you specify metadata like the following only on one of the entities and not both.
[JoinTable(name="ORDER_PRODUCT")]
[JoinColumn(name="ORDER_ID",referencedColumnName="oid")]
[InverseJoinColumn(name="PRODUCT_ID",referencedColumnName="pid")]
The[JoinColumn]tag specifies the foreign key column and all the attributes of the column tag. The
[InverseJoinColumn] tag specifies the reference to the joining entity in the [JoinTable] tag. In this example, join
table "EMP_DEPT" has a column named "DEPID", which refers to the "DEPTID" column of the Department table.
The[JoinTable] tag defines the join table for the many-to-many relationship specifying the join column and inverse
join column. In this example, a join table named "EMP_DEPT" is created in the Offline SQLite DB with a many-tomany relationship between the Employee and Department tables.
When you specify the ignoreLazyLoad parameter as true, the related object is also loaded. For example, if you
have two related objects Address and Customer, and specify loadByPK(Customer,{id:3},true), the Address
object is also loaded.
When you do not specify any value for the ignoreLazyLoad parameter, it takes the default value that is false, and
the related object is not loaded. For example, if you have two related objects Address and Customer, and specify
loadByPK(Customer,{id:3}), the Address object is not loaded.
Cascading options
Cascading lets you specify the operations to be cascaded from the parent object to the associated object. The supported
operations are INSERT, UPDATE, and DELETE. The cascadeType attribute lets you set any of the following values.
ALL If The source entity is inserted, updated, or deleted, the target entity is also inserted, updated, or deleted.
632
PERSIST If The source entity is inserted or updated, the target entity is also inserted or updated.
REMOVE If The source entity is deleted, the target entity is also deleted.
The one-to-one, one-to-many, many-to-one, and many-to-many relationships are all supported by cascading. You can
use code like the following to specify the cascading options:
ManyToMany(cascadeType="ALL or PERSIST or REMOVE")
If you do not specify the cascadeType option, only the source entity is persisted or updated.
When you specify cascadeType='ALL or REMOVE'to remove the parent object and the associated child objects, load
the parent object using load***() method and pass it through session.remove(parentObj). If you do not use this
method of loading, only the parent object gets deleted from SQLite database and the child objects remain.
Note: If you have enabled lazy loading by specifying fetchType='LAZY' at the entity level, when you load a parent object
using load***() method, the child objects are not loaded. When you specify cascadeType='ALL or REMOVE' and
try to delete the parent object by passing it through session.remove(parentObj), it does not delete the child objects.
To overcome this limitation, use the load***() method with ignorelazyloading='true'.
633
634
The following code expands on the session initialization code that was shown above. and shows an openSessionSuccess
event handler that uses the session to save the contents of the remote database in the local image. In this example, users
is the array collection fetched from server:
var dbFile:File = File.userDirectory.resolvePath("basic.db");
var token:SessionToken = syncmanager.openSession(dbFile, 113);
token.addResponder(new mx.rpc.Responder(openSessionSuccess, openSessionFault));
function openSessionSuccess(event:SessionResultEvent):void
{
//Initialize a variable for access to the session.
var session:Session = event.sessionToken.session;
//Save the remote database data in the local database.
//users is the array collection fetched from server
var saveToken:SessionToken = session.saveCache(users);
//Add responder event handlers for successful and failed saves.
saveToken.addResponder(new mx.rpc.Responder(saveSuccess, saveFault));
}
Once you have access to the session, you can get (load) data from the SQLite database, and insert, delete, and update
data database by calling the session objects methods. For details on the session object methods, see ActionScript 3.0
Reference. Alternatively, you can see the standalone Adobe ColdFusion ActionScript Language Reference, which is
accessible through the Documentation link on the Resources page of the ColdFusion Administrator.
Notes:
The SQLite database doesn't validate column types when it creates a table. If you give it an invalid value for column
data type, it creates the column with that type.
When you pass a unique integer ID parameter (one that is not used in the application) to the OpenSession method,
the method creates an intermediate database file, which tracks the client changes to be committed on the server. If
you use more than one database in a single application, use a unique ID for each database. Using a single ID ensures
that you use the correct database for each client-side transaction.
For asynchronous calls (such as SaveCache) that save fetched data in the local database, the call result can be
available by using the session token when the call returns, before the responders are added. This situation occurs if
the SaveCache operation tries to save null data. That is, if the fetch operation returned null data. In such cases, a
responder is not required.
There are two ways to handle this situation:
1
Check whether the result property of the session token returned by the function is null:
if (token.result == null) {
Add the responder here
}
else {
Directly use the token.result
}
2 Check that the ArrayCollection that is input to the SaveCache function is not null. The null response indicates
that the fetch operation did not get a result from the server:
If (ArrayCollection != null) {
Call SaveCache() function
Add Responder to the SaveCache Token
}
else {
Handle the condition here.
}
635
If you call the SaveUpdate Method and a record with the specified primary key doesn't exist, the function inserts
the record. The method updates an existing record only if the primary key exists in the client database.
After you fetch data from the server, use only the SaveCache and SaveCacheUpdate methods to save the fetched
data into client side database. If you use the Save function to store the fetched data, the data is marked for insert on
server on commit, and the data you just got is written back to the server. In this case, a conflict occurs for the server
database primary key. If the server-side logic handles this conflict by ignoring the primary key ID from the client,
and lets the server generate a new ID, then the records are inserted, resulting in multiple copies of the data with
different IDs.
For AIR integration offline support, if you do not globally declare the variables for client side ActionScript classes
but attempt to save the data records fetched from server using session.saveCache() or
session.saveUpdateCache(), you might encounter AIR side error stackstrace with a message similar to the
following:
"Error: The object of type Object does not have the Entity metadata tag at
coldfusion.air::EntityCache/addMetadata()[D:\p4\depot\ColdFusion\cf_main\tools\AIRIntegrat
ion\OfflineSupport\src\coldfusion\air\EntityCache.as:228]"
Conflict management
Conflicts can happen in an offline application when the client modifies data that is already modified on the server. To
identify such a conflict, the session.Commit method passes the following data to the ColdFusion server sync method:
operations: An array of operations to perform INSERT, UPDATE, or DELETE.
clientobjects: An array of new data changes.
636
originalobjects: An array of data that was in the client database before the change. There is no conflict in the
following circumstances:
If your are updating a record and the data on the server is same as the data in the originalobject. The client before
the change had the same data as the server. In this case, the server updates its data source. If the old client data
differs from that on the server, the application must handle the conflict.
If you are inserting a new record. In this case, there is no originalobject value and ColdFusion can insert the record
in the data store.
You use the ColdFusion ObjectEquals function to identify conflicts. Pass the function the new instance of cfc from the
client and the original instance to check if they are equal. If they are equal, the client has been working with the latest
data. If it is not, the server can raise a conflict by returning the sever version of the instance present on the server from
the sync method by creating an instance of CFIDE.AIR.conflict.cfc, setting its serverobject property (its only
property) to the server value of the data, and returning the array of conflict objects to the AIR client.
The following code is an ideal example of sync method that uses ORM methods for syncing operations and also
handles conflicts.
<cffunction name="sync" returntype="any">
<cfargument name="operations" type="array" required="true">
<cfargument name="clientobjects" type="array" required="true">
<cfargument name="originalobjects" type="array" required="false">
<cfset conclits = ArrayNew(1)>
<cfset conflictcount = 1>
<cfloop index="i" from="1" to="#ArrayLen( operations )#">
<cfset operation = operations[i]>
<cfset clientobject = clientobjects[i]>
<cfset originalobject = originalobjects[i]>
<cfif operation eq "INSERT">
<cfset obj = ORMGetSession().merge(clientobject)>
<cfset EntitySave(obj)>
<cfelseif listfindnocase("UPDATE,DELETE",operation) neq 0>
<cfset serverobject = EntityLoadByPK("employee",originalobject.getId())>
<cfif not isdefined('serverobject') >
<cflog text="CONFLICT::SERVER OBJECT NOT FOUND, RECORD MAY BE DELETED ALREADY">
<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>
<cfset conflict.clientobject = clientobject>
<cfset conflict.originalobject = originalobject>
<cfset conflict.operation = operation>
<cfset conflicts[conflictcount++] = conflict>
<cfcontinue>
</cfif>
<cfset isNotConflict = ObjectEquals(originalobject, serverobject)>
<cfif isNotConflict>
<cfif operation eq "UPDATE">
<cfset obj = ORMGetSession().merge(clientobject)>
<cfset EntitySave(obj)>
637
The CFC handling of the conflict depends on your application. In some cases, it can be appropriate to ignore the
conflict and update the server data source with the new client data. In many cases, as in the preceding example, the
CFC informs the client about the conflict by returning the server value of the data.
On the client side, you use code such as the following to register the method that handles the conflict that the server
returns.
syncmanager.addEventListener(ConflictEvent.CONFLICT, conflictHandler);
function conflictHandler(event:ConflictEvent):void
{
var conflicts:ArrayCollection = event.result as ArrayCollection;
var token:SessionToken = session.keepAllServerObjects(conflicts);
token.addResponder(new mx.rpc.Responder(conflictSuccess, conflictFault));
}
The conflictevent object contains an array of conflict objects that contain the clientinstance, originalinstance and the
serverinstance. To accept the server's data, the application calls keepAllServerObjects, which takes an ArrayCollection
that was passed to the conflict handler, or call the keepServerObject that takes an individual Conflict instance as shown
in the following code. This conflict handler simply accepts any returned server object.
function conflictHandler(event:ConflictEvent):void
{
var conflicts:ArrayCollection = event.result as ArrayCollection;
var conflict:Conflict = conflicts.getItemAt(0);
var token:SessionToken = session.keepServerObject(conflict);
token.addResponder(new mx.rpc.Responder(conflictSuccess, conflictFault));
}
When the client does an update after the server data was updated. In this case, the client was using an old instance
of data and not the latest data on the server. The server can inform the client by creating an instance of conflict.cfc
in the sync method and setting the server instance on it. On the client side, you can call the keepServerObject
function in the conflict handler to resolve the conflict by updating the client database with the server instance.
638
When the client does an update but that record no longer exists on the server. Again, a conflict can be passed to the
client from the server by creating an instance of Conflict.cfc and returning it. There is no need to set a serverobject
property, as there is no server instance of the inserted data.
When the client did an insert, but for example, the server data uses an autoincrement primary key field. The server,
therefore, does not use the primary key inserted by the client. To inform the client of the correct key field value, the
server returns the conflict cfc instance with the server instance. The ActionScript Calling keepServerObject method
can then update the local data with the new primary key value from the server.
Note: After a commit or conflict resolution, it is recommended to synchronize the client database with the server data
source, because the server can have new data available from other clients.
ActionScript has a few reserved keywords. When you name the Class/SQLite table, ensure that you do not use any of
the reserved keywords. For example, Order is an ActionScript reserved keyword. If you name a table or class as Order,
the table creation fails. To avoid this name conflict, use the [Table(name="OrderTable")] metadata tag to override
the default name. Your code for the Order.as class could look something like the following:
package test
{
[Entity]
[Table(name="OrderTable")]
public class Order
{
public function Order()
{
}
[Id]
public var oid:uint;
public var name:String;
[ManyToMany(targetEntity="test::Product",cascadeType='ALL')]
public var products:Array;
}
}
639
Customer.as
package onetoone
{
[Bindable]
[RemoteClass(alias="AIRIntegration.custome r")]
[Entity]
public class Customer
{
[Id]
public var cid:int;
public var name: String;
[OneToOne(cascadeType='ALL',fetchType="EAGER")]
[JoinColumn(name="add_id",referencedColumnName="aid")]
public var address:Address;
}
}
Address.as
package onetoone
{
[Bindable]
[RemoteClass(alias="AIRIntegration.address")]
[Entity]
public class Address
{
[Id]
public var aid:int;
public var street:String;
}
}
MainApplication.mxml
Add code like the following in the MainApplication.mxml file to perform CRUD operations on the database.
Note: For Customer.as and Address.as ActionScript classes, global variables have been declared.
640
var
var
var
var
cusColl:ArrayCollection;
syncmanager:SyncManager;
add:Address;//global variable for address.as
cus:Customer; //global variable for customer.as
641
642
643
644
Alert.show("Commit Failed::"+event.error);
}
private function loadFault(event:SessionFaultEvent):void
{
Alert.show("Load Failed::"+event.error);
}
private function updatefualt(event:SessionFaultEvent):void
{
Alert.show("update fault"+event.error);
}
private function savefault(event:SessionFaultEvent):void
{
Alert.show("Save Fault::"+event.error);
}
]]>
</mx:Script>
<mx:Button click="commit()" name="commitbutton"
label="Commit/write local data to Server">
</mx:Button>
</mx:WindowedApplication>
Server-side code
Create the following cfc files - Application.cfc, Customer.cfc, Address.cfc, and Cusmanager.cfc with code like the
following. The AIR client interacts with the Cusmanager.cfc file, in which you specify the code to fetch and sync the
data back to the server.
Application.cfc
<cfcomponent>
<cfset
<cfset
<cfset
<cfset
</cfcomponent>
this.name = "OneTonOneExample">
this.datasource="testorm">
this.ormenabled="true">
this.ormsettings={dialect = "MicrosoftSQLServer"}>
Customer.cfc
<cfcomponent persistent="true">
<cfproperty name="cid" fieldtype="id" >
<cfproperty name="name" >
<cfproperty name="address" fieldType='one-to-one'
CFC="address" fkcolumn='aid' cascade='all' >
</cfcomponent>
Address.cfc
<cfcomponent persistent="true">
<cfproperty name="aid" fieldtype="id" >
<cfproperty name="street" >
</cfcomponent>
645
Cusmanager.cfc
<cfcomponent implements="CFIDE.AIR.ISyncManager">
<!----Fetch method--->
<cffunction name="fetch" returnType="Array" access="remote">
<cfset cus = ArrayNew(1)>
<cfset cus = EntityLoad("customer")>
<cfreturn cus>
</cffunction>
<!----SYNC method--->
<cffunction name="sync" returntype="any">
<cfargument name="operations" type="array" required="true">
<cfargument name="clientobjects" type="array" required="true">
<cfargument name="originalobjects" type="array" required="false">
<cfset conclits = ArrayNew(1)>
<cfset conflictcount = 1>
<cfloop index="i" from="1" to="#ArrayLen( operations )#">
<cfset operation = operations[i]>
<cfset clientobject = clientobjects[i]>
<cfset originalobject = originalobjects[i]>
<cfif operation eq "INSERT">
<cfset obj = ORMGetSession().merge(clientobject)>
<cfset EntitySave(obj)>
<cfelseif listfindnocase("UPDATE,DELETE",operation) neq 0>
<cfset serverobject = EntityLoadByPK("employee",originalobject.getcid())>
<cfif not isdefined('serverobject') >
<cflog text="CONFLICT::SERVER OBJECT NOT FOUND, RECORD MAY BE DELETED ALREADY">
<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>
<cfset conflict.clientobject = clientobject>
<cfset conflict.originalobject = originalobject>
<cfset conflict.operation = operation>
<cfset conflicts[conflictcount++] = conflict>
<cfcontinue>
</cfif>
<cfset isNotConflict = ObjectEquals(originalobject, serverobject)>
<cfif isNotConflict>
<cfif operation eq "UPDATE">
<cfset obj = ORMGetSession().merge(clientobject)>
<cfset EntitySave(obj)>
<cfelseif operation eq "DELETE">
<cfset obj = ORMGetSession().merge(originalobject)>
646
<cfset EntityDelete(obj)>
</cfif>
<cfelse><!----Conflict--->
<cflog text = "is a conflict">
<cfset conflict = CreateObject("component","CFIDE.AIR.conflict")>
<cfset conflict.serverobject = serverobject>
<cfset conflict.clientobject = clientobject>
<cfset conflict.originalobject = originalobject>
<cfset conflict.operation = operation>
<cfset conflicts[conflictcount++] = conflict>
<cfcontinue>
</cfif>
</cfif>
</cfloop>
<cfif conflictcount gt 1>
<cfreturn conflicts>
</cfif>
</cffunction>
</cfcomponent>
Supports Self Join relationships for one-to-one, one-to-many, and many-to-many database relationships.
Supports both Array and ArrayCollection for use in ActionScript Entity to represent a collection in a database
relationship.
ActionScript ORM logs all the SQL statements that ORM uses to persist entities into the SQLite database.
New APIs keepClientObject and keepAllClientObjects to ensure that the server updates are not retained
when ColdFusion server raises conflict.
The class SessionToken is dynamic and therefore, data can be stored on the token returned from the ORM APIs.
Supports autocommit mode
647
Parameters
Parameter
Description
strategy
UUID uses the Flash UUID API to generate the ID (used for primary key of type string) or INCREMENT (for primary key
of type int).
initialValue
Applies only for INCREMENT strategy. Specifies the initial value of the primary key. The default value is 0.
incrementBy
Applies only for INCREMENT strategy. Specifies the integer with which the value must be incremented to generate the
primary key.
If the ID value is not present in the object, the value is generated and is assigned the primary key value. If the key value
is already present on the object instance, then the key generation is ignored.
For integer primary keys, the database table is checked for the presence of existing primary keys. If the highest key
value is greater than the initialValue, then the key that is generated next will be an increment of the highest key
value. For example, if the initialValue that you specify is 1, and the database (already) has a key value 5, then the
next key is generated with the value 6 (5+1, if incrementBy is set to 1).
Example
//Integer Primary Keys
===========
package test.apollo.CFSQLiteSupport.INCREMENTPK
{
[Entity]
[RemoteClass(alias="Customer")]
public class Customer
{
public function Customer()
{
}
[Id]
[GeneratedValue(strategy="INCREMENT",initialValue=5,incrementBy=2) ]
public var cid:int;
public var name:String;
[OneToOne(mappedBy="customer")]
public var ord:Order;
}
}
648
For details on EncryptionKeyGenerator, see the section Using the EncryptionKeyGenerator class to obtain a secure
encryption key in Developing Adobe AIR 1.5 Applications with Flex.
649
650
[ManyToMany(targetEntity="onetoone::Customer",fetchType="EAGER")]
[JoinTable(name="CUSTOMER_PARENTS_MAPPINGS")]
[JoinColumn(name="CUST_ID",referencedColumnName="cid")]
[InverseJoinColumn(name="PARENT_ID",referencedColumnName="cid")]
public var parents:Array;
Server-side configuration
See the section Changes in the XML configuration files for Flash Remoting in ColdFusion 9 and ColdFusion 9.0.1
on page 674.
651
The log target is the TraceTarget where all the trace statements appear. The log target can be set to any other log using
the Flash APIs.
Parameters
Parameter
Description
mx.collections.ArrayCollection
Example
private function conflictHandler(event:ConflictEvent):void
{
// Alert.show("Server returned a Conflict !");
var conflicts:ArrayCollection = event.result as ArrayCollection;
// Ignore Server data and retain client Data in SQLite DB
var token:SessionToken = session.keepAllClientObjects(conflicts);
token.addResponder(new mx.rpc.Responder(conflictSuccess, conflictFault));
}
keepClientObject
Description
Ensures that the client object is retained instead of the one from the server (despite server raising data conflict).
The API also ensures that the retained client object is not sent to the server as a new operation on sync.
652
Returns
An instance of coldfusion.air.SessionToken associated with keepClientObject call.
Syntax
public function keepClientObject(conflict:coldfusion.air.Conflict):SessionToken
Parameters
Parameter
Description
coldfusion.air.Conflict
Example
See the example in the section keepAllClientObjects. For keepClientObject, the only difference is that you must
iterate over each conflict in the conflictarray collection.
Offline AIR SQLite API enhancements
The following new parameters for openSession:
New Parameters
Type
Required/Optional
Description
encryptionKey
ByteArray
Optional
cacehDirectory
File
Optional
653
If true, the changes in the local database are committed to the server when the save, saveUpdate, and remove
methods are used as shown here:
private var syncmanager:SyncManager = new SyncManager();
syncmanager.autoCommit = true;
This functionality helps you minimize the conflicts during the synchronization with the server, particularly in the case
of auto-generation of primary key on client and serverside.
Note: Assume that the server database generates primary keys and you choose to generate primary key on client SQL Lite
table (as shown in the example). This scenario results in a conflict which the application developer must resolve. An
option is to design your application in such a way that you minimize conflicts between client and server objects. In this
case, you can set client object primary keys as null or empty string before saving data to the database server using
serverside ORM EntitySave function.
654
Document (cfdocument)
Image (cfimage)
Mail (cfmail)
PDF (cfpdf)
Pop (cfpop)
These classes are part of coldfusion.service.mxml package, distributed in the cfservices.swc file. You normally use these
classes in MXML tag format, using the cf namespace identifier, as in the following line:
<cf:Image id="image" action="AddBorder" source="Uploaded Image server URL" thickness="5"
color="Blue"/>
To use a ColdFusion service in an application built with Flex, you use the Config class to establish the connection, and
then use the other classes to access the ColdFusion services.
In ColdFusion 9, you can also specify the remoting destination in the Config class as well as all the proxy tags.
Note: To use ColdFusion services from Flex and AIR, you must enable access to the services as described in "Enable
ColdFusion Services" in the ColdFusion Web Services section.
Description
serviceUserName
The userName set in the ColdFusion Administrator with the permission to access the specific service being
requested.
servicePassword
The password set in the ColdFusion Administrator for the user name.
cfServer
cfPort
655
Attribute
Description
cfContextRoot
secureHTTP
Boolean value specifying whether to use http or https to run the service.
destination
The destination attribute can be used to specify a user defined remoting destination in WEB-INF/flex/remotingconfig.xml. If not specified, default ColdFusion destination is used.
You normally specify the config class using an MXML tag as follows:
<cf:Config id="conf" cfServer="CF Server IP Address/HostName" CFPort="HTTP Port on Which CF
accepts request" destination="UserDefinedRemotingDestination" >
You can also override the server settings directly in the service tag, for example:
<cf:Image id="image" action="AddBorder" cfServer="IP Address" cfPort="Port number"
source="Uploaded Image server URL" thickness="5" color="Blue"
destination="UserDefinedRemotingDestination" />
The UPLOAD_URL constant contains the URL on the ColdFusion server of the Upload service, relative to cf_webroot.
The extractURLFromUploadResponse() method takes response returned by the Upload service as input and
returns the path of the uploaded file on the ColdFusion server.
You use the UPLOAD_URL constant and the extractURLFromUploadResponse() function in the following workflow
to upload a file and use the file in a ColdFusion service.
Use the ActionScript flash.net.FileReference APIs and the Util.UPLOAD_URL variable to upload an Image,
PDF, or mail attachment to the server on which the action has to be performed. The upload URL to supply to the
flash.net.FileReference APIs can be constructed as follows in the ActionScript part of the application:
uploadURL.url =
"http://"+conf.cfServer+":"+conf.cfPort+"/"+conf.contextRoot+"/"+Util.UPLOAD_URL;
var variables:URLVariables = new URLVariables();
variables.serviceusername = conf.serviceUserName;
variables.servicepassword = conf.servicePassword;
uploadURL.data = variables;
uploadURL.method="POST";
Here, specify "conf.cfServer", "conf.cfPort" and "conf.ContextRoot" in the <cf:Config> tag. Specify
"conf.ContextRoot" only if ColdFusion is deployed as a J2EE application.
Note: The ActionScript FileUpload functionality is out of the scope for this feature hence it is not explained in detail,
but an example of the usage is provided in code in MAIL class section. For further information on FileUpload
functionality see the ActionScript documentation.
2 Once the file is uploaded, the server returns an XML response containing URL of the uploaded file. Use the Util
656
serviceObject.execute()
5 If the action succeeds, the server returns the result. If there is an exception, it returns the fault. Handle the
ResultEvent and FaultEvent objects in the service-specific result handler and fault handler that you specify in
the service tag, or in global handlers that you specify in the <cf:config>. The ResultEvent object contains the URL
of the File on which the operations have been performed. Users can save this file by downloading it on their
machine or rendering it in the application. The FaultEvent object contains the exception details that occurred on
the server while performing the operation.
For granular control over proxy classes, you can get hold of the underlying RemotObject by using getRemoteObject()
method on the proxy class object. For example, for <cf:Mail id=mailId>, you can get it using the following code in
ActionScript.
var mailobject:RemoteObject = mailId.getRemoteObject();
657
}
if(cfserviceusername.text == "" && cfservicepassword.text == "")
{
Alert.show("CF Service UserName and Password are not required to test
CF server connectivity but they will be required while using the CF
services","Note");
}
service.url = CF_HTTPURL;
service.method = "POST";
service.addEventListener(ResultEvent.RESULT,httpResult);
service.addEventListener(FaultEvent.FAULT,httpFault);
service.send();
}
public function httpResult(event:ResultEvent):void
{
Alert.show("Connection with ColdFusion server Successful","Connection Status");
}
public function httpFault(event:FaultEvent):void
{
Alert.show("ColdFusion server could not be reached, Make sure credentials are
correct and CF server is running","Error");
}
private function checkCollapse(event:MouseEvent):void
{
if( event.clickCount == 2)
{
currentState = currentState == "collapsed" ? "":"collapsed";
}
}
private function rememberCredential():void
{
var data:ByteArray = new ByteArray();
data.writeUTFBytes(cfip.text);
En cryptedLocalStore.setItem('IP', data );
var data:ByteArray = new ByteArray();
data.writeUTFBytes(cfprt.text);
Encr yptedLocalStore.setItem('PORT', data );
var data:ByteArray = new ByteArray();
data.writeUTFBytes(cfcnxtrt.text);
Encrypt edLocalStore.setItem('CONTEXT', data );
var data:ByteArray = new ByteArray();
data.writeUTFBytes(cfserviceusername.text);
Encr yptedLocalStore.setItem( 'USER', data );
var data:ByteArray = new ByteArray();
data.writeUTFBytes(cfservicepassword.text);
Encrypted LocalStore.setItem('PASS', data );
}
private function retrieveCredential():void
{
try{
cfip.text = EncryptedLocalStore.getItem('IP').toString();
cfprt.text = EncryptedLocalStore.getItem('PORT').toString();
658
cfcnxtrt.text = EncryptedLocalStore.getItem('CONTEXT').toString();
cfserviceusername.text = EncryptedLocalStore.getItem('USER').toString();
cfservicepassword.text = EncryptedLocalStore.getItem(' PASS').to String();
}
catch(e:Error)
{
}
}
private function resetCredential():void
{
EncryptedLocalStore.reset();
cfip.text = "";
cfprt.text = "";
cfcnxtrt.text = "";
cfserviceusername.text = "" ;
cfservicepassword.text = "";
}
]]>
</mx:Script>
<mx:ControlBar>
<mx:Label text="CFServer IP"/>
<mx: TextInput id="cfip" text="" width="
70"/>
<mx:Label text="CFServer Port"/>
<mx:TextInput id="cfprt" text="" width="40"/>
<mx:Labeltext="CFServer Context Root (if any)"/>
<mx:TextInput id="cfcnxtrt" text="" width="70"/>
<mx:Label text="CFService UserName"/>
<mx:TextInput id= "cfserviceusername" text="" width="70"/>
<mx:Label text="CFService Password"/>
<mx:TextInput displayAsPassword="true" id="cfservicepassword" text="" width="70"/>
<mx:Button id="testconn" label="Test Connection" click="testConnection()"/>
<mx:Button id="save" label=" Remember"click="rememberCredential()"/>
<mx:Button id="reset" label ="Reset" click = "resetCred e n tial()"/>
</mx:ControlBar>
<mx:states>
<mx:State name="collapsed">
<mx: SetProperty name="height" value="10"/>
</mx:State>
</mx:states>
</mx:Panel>
659
660
called after user selects files form the browse dialogue box.
private function selectHandler(event:Event):void
{var i:int;
for (i=0;i < event.currentTarget.fileList.length; i ++)
{
fileslist.addItem(event.currentTarget.fileList[i]);
attachList.text += event.currentTarget.fileList[i].name + ", ";
}
}
private function uploadFiles(event:Event):void
{
if (fileslist.length > 0)
{
fileRef = FileReference(fileslist.getItemAt(0));
fileRef.addEventListener(Event.COMPLETE, completeHandler);
fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,dataHandler);
fileRef.upload(uploadURL);
}
else if (fileslist.length == 0)
{
sendmail();
}
}
// called after a file has been successfully uploaded | We use this as well to check if there
are any files left to upload and how to handle it
private function completeHandler(event:Event):void
{
// Alert.show("File Uploaded successfully");
fileslist.removeItemAt(0);
if (fileslist.length > 0)
{
uploadFiles(null);
}
}
//called after file upload is done and Data has been returned from Server
private function dataHandler(event:DataEvent):void
{
attachCollection[urlcnt++] = {"file":
Util.extractURLFromUploadResponse(event.data.toString())};
if (fileslist.length == 0)
sendmail();
}
private function sendmail():void
{
mailtest.execute();
}
public function handleResult(event:ColdFusionServiceResultEvent):void
{
from.text="";too.text=""; cc.text="";bcc.text="";
subject.text="";mailbody.text="";
attachList.text=""; fileslist.removeAll();
661
662
cfServer="{cred.cfip.text}"
cfPort="{int(cred.cfprt.text)}"
cfContextRoot="{cred.cfcnxtrt.text}"
servicePassword="{cred.cfservicepassword.text}"
serviceUserName="{cred.cfserviceusername.text}"
/>
<cf:Mail id="mailtest"
server="xx.xxx.xx.xxx"
to="{too.text}" bcc="{bcc.text}" cc="{cc.text}"
failTo="[email protected]" replyTo="[email protected]"
subject="{subject.text}" content="{mailbody.text}"
from="{from.text}"
attachments="{attachCollection}"
type="text" charset="utf-8" mailerId="CF" priority="1"
timeout="60" useTLS="true" wrapText="5"
result="handleResult(event)"
fault="handleError(event)"
/>
</mx:WindowedApplication>
663
<cf:Config
id="configid"
cfServer="127.0.0.1"
cfPort="80"
servicePassword="service"
serviceUserName="service"/>
<!-- Add border-->
<cf:Image
id="img"
action="addborder"
color="red"
thickness="5"
source="http://127.0.0.1:80/GetExifmetaData.jpg"
result="handleResult(event)"
fault="handleError(event)"/>
<mx:Image id="retImage"/>
</mx:Application>
Batch operation
A batch operation lets you perform multiple image manipulations on an image as part of one operation, instead of
performing the operations individually. You upload an image to the server, use the batch operation to perform
multiple Image operations on it, and get the modified image back from the server. To use this action, use an associative
array of actions and corresponding attributes. It is easier to create an associative array in ActionScript than MXML.
The following example shows code to create the associative array with the action information and perform the batch
operation:
ActionScript Part:
[Bindable]
public var attributes:Array =
[{AddBorder:{color:"Red",thickness:"50"}},
{Resize:{width:"50%",height:"50%",interpolation:"blackman",blurfactor:"2"}},
{Flip:{transpose:"270"}}]
MXML Part:
<!-- batch operation -<cf:Image id="img" action="batchoperation"
source="http://localhost:8500/cat.jpg"
attributes="{attributes}"/>
664
665
pdfParam="{pdfparams}" keepBookmark="true"
resultHandler="handleExtractResult"
errorHandler="handleExtractError"/>
<!-- set info-->
<cf:Pdf id="pdftest" action="setinfo"
source="http://localhost:8500/1page.pdf" info="{elements}"
resultHandler="handleExtractResult"
errorHandler="handleExtractError"/>
<!-- thumbnail-->
<cf:Pdf id="pdftest" action="thumbnail"
source="http://localhost:8500/EC205W_JoelGeraci.pdf"
resultHandler="handleThumbnailResult"
errorHandler="handleThumbnailError"/>
<!-- ProcessDDX-->
<cf:Pdf id="pdftest" action="processddx"
ddxString="{ddx}" outputFiles="{outputFiles}" result="handleProcessDDXResult"
fault="handleProcessDDXError"/>
You represent each chart's data as an array of objects, each of which contains an item element and a value element.
You use these arrays as the chartdata elements of the chartSeries object.
You call the document object execute() function to run the service.
The following example shows how you can use the chart service:
666
667
chartHeight = "500"
chartWidth = "600"
dataBackgroundColor = "yellow"
font = "ariel"
fontBold = "yes"
fontItalic = "yes"
fontSize = "12"
foregroundColor = "red"
gridLines = "2"
labelFormat = "number"
markerSize = "10"
showBorder = "yes"
showLegend = "yes"
showMarkers = "yes"
showxGridLines="yes"
showyGridLines="yes"
tipBgColor="blue"
tipStyle = "MouseOver"
title = "AIR Integration testing"/>
</mx:Application>
You specify the cfdocument attributes as Document object properties. You specify document content that is not
in a section as a content element of the document object.
You represent document sections in the documentSection element of the document object. The documentSection
element is an arrays of objects, each of which represents a single document section. These objects include a content
element for the section content, an optional documentItem element for the document items, and elements for any
other section attributes.
You represent all document items in a document section (or the document object) as an array of objects with type
and content elements. The array element type field specifies whether the item is a header, footer, or page break. You
specify the document item array as a documentItem element of the document object or a documentSection object.
The following excerpt from the full example shows how to create sections and items and add them to a document:
668
[Bindable]
var docItem:Array = [{type:"header",content:"<font size='-3'>
<i>Salary Report</i></font>"},{type:"footer",
content:"<font size='-3'>
Page #cfdocument.currentpagenumber#</font>"}];
[Bindable]var docSectionItem:Array = [{content:"<table width='95%'
border='2' cellspacing='2' cellpadding='2' >
<tr><th>Salary</th></tr><tr>
<td><font size='-1'>John</font></td>
<td align='right'><font size='-1'>Guess What</font></td></tr>
<tr><td align='right'><font size='-1'>Total</font></td>
<td align='right'><font size='-1'>Peanuts</font></td></tr>",
documentitem:docItem},{content:"content2",documentitem:docItem}];
.
.
.
cfDoc.documentSection = docSectionItem;
669
//Alert.show("httpurl= "+event.result.toString());
}
private function handleError(event:Event):void
{
mx.controls.Alert.show(event.toString());
}
]]>
</mx:Script>
<cf:Config id="configid" cfServer="localhost"
cfPort="80" servicePassword="service" serviceUserName="service" />
<!-- simple case-->
<cf:Document id="doctestnow" action="generate"
format="flashpaper" result="handleResult(event)"
fault="handleError(event)"
content="<table><tr><td>bird</td><td>
1</td></tr><tr><td>fruit</td><
td>2</td></tr><tr><td>rose</td>
<td>3</td></tr></table>"/>
<!--doc item case -->
<!--<cf:Document id="doctestnow" action="generate"
format="flashpaper" result="handleResult(event)"
fault="handleError(event)" documentItem="{docItem}"/>-->
<!-- doc section case-->
<!--<cf:Document id="doctestnow" action="generate"
format="flashpaper" result="handleResult(event)"
fault="handleError(event)" documentSection="{docSection}"/>-->
<!-- doc section and doc item case
<cf:Document id="doctestnow" action="generate"
format="flashpaper" result="handleResult(event)"
fault="handleError(event)" documentSection="{docSectionItem}" />-->
<mx:SWFLoader source="{res}"/>
</mx:Application>
670
671
Note: To use the LiveCycle Data Services ES assembler, the Flex application must be running on Flex Data Services 2.0.1
or LiveCycle Data Services 2.5, although not every feature is supported in Flex Data Services 2.0.1.
The Flex server includes a ColdFusion Data Service adapter. The adapter processes changes to data to ensure that data
on the client is synchronized with back-end data and conversely; it executes the sync, fill, count, and get
operations, identifies conflicts, and passes results to LiveCycle Data Services ES.
ColdFusion includes the LiveCycle Data Services ES assembler; along with the ActionScript translator, it converts the
input arguments where necessary and translates the return values.
Note: If you install LiveCycle Data Services ES, ColdFusion does not map .SWF files. This means that all .SWF files are
served through the ColdFusion web application instead of the web server.
672
The following diagram shows the process that LiveCycle Data Services ES and ColdFusion use when a Flex application
calls a method in a ColdFusion component:
1 A Flash client requests data that the LiveCycle Data Management Service adapter handles.
2 Flex calls a fill, sync, get, or count method in the Data Service.
3 If you are running LiveCycle Data Services ES remotely, copy the lcds2.6_install/resources/lib/flex-*.jar files to the
running LiveCycle Data Services ES remotely, the adapter sends the request by using Java Remote Method
Invocation (Java RMI).
5 The LiveCycle Data Services ES assembler and the ActionScript translator convert ActionScript 3.0 data types to
ColdFusion server.
8 The ColdFusion server sends the results to the LiveCycle Data Services ES assembler.
9 The LiveCycle Data Services ES assembler and the ActionScript translator convert ColdFusion values to the
appropriate ActionScript 3.0 data types, and then the assembler sends the results to the ColdFusion Data Service
adapter.
10 The ColdFusion Data Service adapter sends the results to the LiveCycle Data Management Service.
11 The LiveCycle Data Management Service passes the results to the Flash client.
Note: The RMI registry, which facilitates communication between the ColdFusion Data Service assembler and the remote
LiveCycle Data Management Service uses port 1099, which is the default port for Java RMI. You can change the port
number by adding -Dcoldfusion.rmiport=1234 to the Java JVM arguments on both the ColdFusion server and the Flex
server.
673
2 Create the Flex application, in which you define a DataService component in MXML or ActionScript. The
DataService component calls methods on a server-side Data Management Service destination to perform activities
such as filling client-side data collections with data from remote data sources and synchronizing the client and
server versions of data.
3 Configure a destination for the ColdFusion Data Service adapter so that the Flex application to connect to the
ColdFusion back-end application. For more information, see Configuring a destination for the ColdFusion Data
Service adapter on page 673.
4 Write your ColdFusion CFCs. For more information, see Writing the ColdFusion CFCs on page 680.
Note: To make creating the CFCs easier, ColdFusion includes wizards that you can use in Flash Builder. For more
information, see Using the ColdFusion Extensions for Eclipse on page 1334.
5 Test your application by using Flex.
You specify channel definitions and enable ColdFusion-specific debugging output in the Flex console in this file.
Change the port numbers in the services-config.xml file for the RTMP channels if you run more than one
ColdFusion instance with the integrated LiveCycle Data Services ES.
2 data-management-config.xml
This file is added only when you install LiveCycle Data Services 2.6.1 manually. You specify adapters and
destinations in this file.
To ensure that Flex recognizes the LiveCycle Data Services ES assembler and can transport messages to and from the
destination, by doing the following:
Enhanced Flash Remoting supports Circular references for objects which are not supported in old Flash Remoting
(ColdFusion 8).
674
ColdFusion 9 supports Old XML configurations files as well, but with these files it will not be using Enhanced Flash
Remoting. To take advantage of Enhanced Flash Remoting, while migrating your old XML files to ColdFusion9, you
should make sure that they comply with new XML structural changes.
If you are using LCDS with ColdFusion 9, then Flash Remoting works on LCDS 2.6.1. Ensure that you are on LCDS
2.6.1 to make use of the enhanced Flash Remoting.
ColdFusion 9 is backward compatible with old Flash Remoting as well, to support LCDS2.5 and prior releases.
Now in a case, where you require to continue with LCDS 2.5 or prior versions, it will not be possible for you to use
enhanced Flash Remoting offered by ColdFusion 9. In this scenario, you can continue working with LCDS2.5 and
prior versions with old style XML configuration files.
To use the old style flash remoting with LCDS 2.5, first remove the existing ColdFusion 9 flex-*.jar files from
cfusion/lib by taking a backup of the files and placing the LCDS2.5 flex-*.jar files in the cfusion\lib directory.
After this, you can continue to use the old style (ColdFusion 8) XML configuration files by placing them under WEBINF\Flex\ directory. Also make sure that WEB-INF\ flex\jar\cfdataserviceadapter.jar is also present.
For detailed steps on integrating LCDS2.5 with ColdFusion, see the technote on www.adobe.com.
Another case here could be that you have integrated LCDS 2.6.1 with ColdFusion 9 and still you want to use old Flash
Remoting. You can implement this scenario, but in this case you cannot take advantages offered by enhanced Flash
Remoting.
Changes in the XML configuration files for Flash Remoting in ColdFusion 9 and ColdFusion
9.0.1
For ColdFusion 9, the structure of the services-config.xml file has changed. These structural changes are:
A new <coldfusion> tag has been added under the <properties> in <channel-definition>, where the
<access>, <use-accessor>, <use-structs>, and <property-case> tags are defined.
In old ColdFusion 8 style remoting, these tags used to be present in the destination, defined in data-managementconfig.xml file.
However, now you need to either set the <instantiate-types> to true or remove it from the services-config.xml
file.
The <enable-small-messages> flag must be set to false under the serialization property.
Note: In case you create custom channel definition on your client side by overriding the XML-based channel
configurations, you still need to set enableSmallMessages flag to false. This is shown in the following code example:
<mx:ChannelSet id="myChannelSet">
<mx:channels>
<mx:AMFChannel enableSmallMessages="false"
url="http://localhost:8500/flex2gateway/cfamfpolling" id="cfAMFPolling"
pollingEnabled="true" pollingInterval="8"/>
</mx:channels>
</mx:ChannelSet>
In ColdFusion 9, the endpoint class names have been changed from the endpoint classes in ColdFusion 8. The
following table provides a list of channel-definitions and their corresponding endpoint classes:
675
Channel-definition
ID
my-cfamf
coldfusion.flash.messaging.CFAMFEndPoint
flex.messaging.endpoints.AMFEndpoint
cf-polling-amf
coldfusion.flash.messaging.CFAMFEndPoint
flex.messaging.endpoints.AMFEndpoint
my-cfamf-secure
coldfusion.flash.messaging.SecureCFAMFEnd
Point
flex.messaging.endpoints.SecureAMFEn
dpoint
cf-rtmp
coldfusion.flash.messaging.CFRTMPEndPoint
flex.messaging.endpoints.RTMPEndpoin
t
Note: For LiveCycle Data Services ES, the cf-polling-amf and cf-rtmp channel definitions are used.
Endpoint Class
my-streaming-amf
coldfusion.flash.messaging.CFStreamingAMFEndPoint
secure-streaming-amf
coldfusion.flash.messaging.SecureCFStreamingAMFEndPoint
Endpoint Class
my-nio-amf
coldfusion.flash.messaging.CFNIOAMFEndPoint secure-nio-amf
secure-nio-amf
coldfusion.flash.messaging.SecureCFNIOAMFEndPoint
secure-cf-rtmp
coldfusion.flash.messaging.SecureCFRTMPEndPoint
my-nio-amf-stream
coldfusion.flash.messaging.CFStreamingNIOAMFEndPoint
secure-nio-amf-stream
coldfusion.flash.messaging.SecureCFStreamingNIOAMFEndPoint
Note: This construct is not considered when ColdFusion Array is sent to LCDS Flex Client. In this case, ColdFusion
Array always gets translated to ActionScript ArrayCollection.
All the other files that need to be referenced from services-config.xml are now included in services-config.xml.
In ColdFusion 8, the services-config.xml files looked similar to the following:
676
677
<properties>
<idle-timeout-minutes>20</idle-timeout-minutes>
<serialization>
<enable-small-messages>false</enable-small-messages>
</serialization>
<coldfusion>
<access>
<use-mappings>true</use-mappings>
<method-access-level>remote</method-access-level>
</access>
<use-accessors>true</use-accessors>
<use-structs>false</use-structs>
<property-case>
<force-cfc-lowercase>false</force-cfc-lowercase>
<force-query-lowercase>false</force-query-lowercase>
<force-struct-lowercase>false</force-struct-lowercase>
</property-case>
</coldfusion>
</properties>
</channel-definition>
678
Element
Description
access
Define the resolution rules and access level of the CFC being invoked
use-accessors
Whether the Value Object CFC has getters and setters. Set the value of useaccessors to true if there are getters and setters in the Value Object CFC. However,
if you set use-accessors to true and there are no getters and setters in the value
object CFC, ColdFusion sets the value of any property of the value object CFC in the
this scope. If your CFC does not have any getters and setters, you can increase
performance by setting this to false so that ColdFusion does not spend time looking
for these methods. The default value is true.
use-structs
force-cfc-lowercase
Whether to make property names, query column names, and structure keys lowercase
when converting to ActionScript. Query column names must precisely match the case
of the corresponding ActionScript variables. The default value is false.
force-query-lowercase
force-struct-lowercase
use-mappings
A Boolean value specifying whether the source attribute can be relative to (start with)
a ColdFusion mapping. The default value is true.
method-access-level
Specifies the access attribute values a CFC must have for ColdFusion to respond to
the request. The following values are valid:
remote
Flex can access only functions that specify remote access. (the default)
public
Flex can access functions that specify both remote or public access.
Specifying a destination
A destination is the server-side service or object that you call. You configure Data Management destinations in the
data-management-config.xml file.
The destination contains the following elements:
Element
Description
destination id
adapter-ref
The name of the adapter to use. You use the ColdFusion adapter-ref element for any ColdFusion
specific destinations.
channels-ref
Use the ColdFusion configured channels that have the instantiate-types flag set to false.
component
679
Element
Description
scope
The scope, which can be application, session, or request. The application value specifies that
there is only one instance; request specifies that there is a new CFC for each call. ColdFusion does not
support session. (Do not confuse this setting with the ColdFusion variable scope; they are not related.)
hostname
The host name or IP address of the ColdFusion host. If you are running LiveCycle Data Services as part of
ColdFusion you do not specify a host name or IP address; however, if you are running LiveCycle Data
Services ES remotely, specify a host name or IP address.
identity
The ID of the ColdFusion Data Management server as configured in the ColdFusion Administrator.
This is required only if you are accessing a ColdFusion server remotely using RMI and have more than
one instance of ColdFusion on a machine.
remote-username
remote-password
Credentials to pass to the assembler CFC for all clients. It is preferable to use the ActionScript
setRemoteCredentials() API on the client.
identity property
The property or list of properties that are the primary key in the database.
query-row-type
Optional. If the assembler fill method returns a query, define an ActionScript type for each row in the
query that the ArrayCollection returned.
fill-method
Whether to update the results of a fill operation after a create or update operation.
use-fill-contains
Optional. Whether the assembler has a fill-contains method. This method is used to determine
whether to refresh the fill. If the specified method returns true, the fill is re-executed after a create or
update operation. Set use-fill-contains to true only when auto-refresh is set to true. The
default value is false.
auto-refresh
Optional. Whether to refresh the fill after a create or update operation. The default value is true.
ordered
Optional. Whether order is important for this filled collection. Allows performance optimization when
order is not important. The default value is true.
680
For more information, see Configuring the Data Service in Developing Flex Applications, which is included in the
Flex documentation.
Note: The ColdFusion Administrator lets you enable or disable LiveCycle Data Management support. If you are running
more than one instance of ColdFusion, use a unique ID to specify each instance of ColdFusion for which you enable
LiveCycle Data Management support. You do so by specifying the identity in the identity element in the datamanagement-config.xml file.
681
You place the database manipulation functionality directly in the methods in the assembler CFC and create a Value
Object CFC, which is a CFC that contains property definitions and related get and set methods.
To separate the lower level database functionality from the high-level Flex assembler operations, you create a Data
Access Object (DAO) CFC that contains the lower level database functionality. Using this approach, which is the
Bean/DAO methodology, requires that you place the fill, get, sync, and count methods in the assembler CFC. The
methods in the assembler CFC call methods in the DAO CFC that perform the lower level database functions such as
retrieving records. The DAO CFC creates Value Objects, which are CFCs that contain the values. A Value Object is
essentially a row in the result set.
The LiveCycle Data Management Service recognizes the methods: fill, get, sync, and count. The fill method
retrieves records from a database and populates an array with the records. The get method retrieves a specific record.
The sync method lets you keep track of synchronization conflicts by accepting a change list, which is an array of
change objects. The count method returns a number that indicates how many records are in a result set. To perform
any of these database tasks, the Flex application calls the appropriate fill, get, sync, or count method in the
assembler CFC. You can also use a fillContains method, which checks whether to update the results of a fill. For
more information, see Managing fills on page 683.
You can return a Value Object CFC, a query, or an array of CFML structures. Using a query instead of a Value Object
CFC may improve performance. However, ColdFusion cannot handle nested results sets when you use a query. For
example, if one of the CFC properties you are returning from the fill method was populated with another complex
type such as another CFC type, ColdFusion cannot automatically convert a column in the query to an object with a
custom type. In this case, you return an array of CFCs, and the fill method or the read method in the DAO CFC
constructs the correct object.
You can use structures wherever you currently create a ColdFusion component in the Assembler. However, you still
receive CFC Value Objects from Flex. For example, the Change Objects that you receive in the sync method contain
CFCs, assuming that you have a remote alias defined in the ActionScript type.
You can create Value Object CFCs in the get method. However, using the structure functionality, you can create and
return a structure instead of a CFC, because the structures are translated in the same way as CFCs. You can also return
an array of structures from the fill method instead of an array of CFCs, for example, if you have to do processing on
your data and working with CFCs isn't fast enough. Generally, structures are faster than CFCs. You also use structures
when a member of the result object is a complex object. In this case, you create another structure as the value of that
key and provide the __type__ key for it.
You specify the returntype of the fill method as a Value Object CFC, a query, or an array:
1 Value Object:
<cffunction name="fill" output="no"
returntype="samples.contact.Contact[]" access="remote">
2 Query:
682
3 Array of structures:
<cffunction name="fill" output="no"
returntype="array" access="remote">
In addition to specifying the returntype of the fill function depending on whether you are using Value Objects, a
query, or an array of structures, you also do the following in the lower level read function:
Specify the returntype of the read function as the Value Object CFC, a query, or an array, for example:
Loop through the query to create each Value Object based on each row of the query, for example:
<cfloop query="qRead">
<cfscript>
obj = createObject("component",
"samples.contact.Contact").init();
obj.setcontactId(qRead.contactId);
obj.setfirstName(qRead.firstName);
obj.setlastName(qRead.lastName);
obj.setaddress(qRead.address);
obj.setcity(qRead.city);
obj.setstate(qRead.state);
obj.setzip(qRead.zip);
obj.setphone(qRead.phone);
ArrayAppend(ret, obj);
</cfscript>
</cfloop>
If you are using a DAO CFC, edit the read method to return a query instead of an array of CFCs.
683
Ensure that the query column names match the case of the properties in the ActionScript object. Use the
property-case settings in the destination to do so. Set the force-query-lowercase element to false so that
Loop through the query to create the structure that contains the results of the query, for example:
<cfloop query="qRead">
<cfscript>
stContact = structNew();
stContact["__type__"] = "samples.contact.Contact";
stContact["contactId"] = qRead.contactId;
stContact["firstName"] = qRead.firstName;
stContact["lastName"] = qRead.lastName;
stContact["address"] = qRead.address;
stContact["city"] = qRead.city;
stContact["state"] = qRead.state;
stContact["zip"] = qRead.zip;
stContact["phone"] = qRead.phone;
ArrayAppend(ret, duplicate(stContact));
</cfscript>
</cfloop>
Use the __type__ structure element to specify that the Value Object CFC is the type, for example:
stContact["__type_"] = "samples.contact.Contact";
Use the associative array syntax, for example, contact["firstName"] to ensure that you match the case of the
ActionScript property. If you use the other syntax, for example, contact.firstName="Joan", ColdFusion
makes the key name uppercase.
Managing fills
To determine whether to refresh a fill result after an item is created or updated, you include a fillContains method
in the assembler and set both use-fill-contains and auto-refresh to true in the fill-method section of the datamanagement-config.xml file. The following example shows a fill-method section:
<fill-method>
<use-fill-contains>true</use-fill-contains>
<auto-refresh>true</auto-refresh>
<ordered>false</ordered>
</fill-method>
In this example, ordered is set to false because the fill result is not sorted by any criteria. However, if the fill result is
sorted, you set ordered to true. When an item changes in a fill result that is ordered, refresh the entire fill result.
The fillContains method tells the Flex application whether it is necessary to run the fill again after an item in the
fill result has changed. The fillCcontains method returns a value that indicates how the fill be treated for that
change. When the fillContains method returns true, the fill is executed after a create or update operation.
The following example shows the fillContains method signature:
<cffunction name="fillContains" output="no" returnType="boolean" access="remote">
<cfargument name="fillArgs" type="array" required="yes">
<cfargument name="item" type="[CFC type object]" required="yes">
<cfargument name="isCreate" type="boolean" required="yes">
684
A sample fillContains method, which determines whether the fill arguments (part of the first or last name) are
in the Contact item passed to the function, is as follows:
<cffunction name="fillContains" output="no" returnType="boolean"access="remote">
<cfargument name="fillArgs" type="array" required="yes">
<cfargument name="item" type="samples.contact.Contact" required="yes">
<cfargument name="isCreate" type="boolean" required="yes">
<cfif ArrayLen(fillArgs) EQ 0>
<!--- This is the everything fill. --->
<cfreturn true>
<cfelseif ArrayLen(fillArgs) EQ 1>
<!--- This is a search fill. --->
<cfset search = fillArgs[1]>
<cfset first = item.getFirstName()>
<cfset last = item.getLastName()>
<!--- If the first or last name contains the search string, --->
<cfif (FindNoCase(search, first) NEQ 0) OR (FindNoCase(search, last)
NEQ 0)>
<!--- this record is in the fill. --->
<cfreturn true>
<cfelse>
<!--- this record is NOT in the fill. --->
<cfreturn false>
</cfif>
</cfif>
<!--- By default, do the fill.--->
<cfreturn true>
</cffunction>
If you are running LiveCycle Data Services ES locally, you can determine whether a fill operation is a refresh or a
client triggered fill. You do so by calling the DataServiceTransaction.getCurrentDataServiceTransaction().isRefill()
method in your ColdFusion application as follows:
<cfscript>
dst = CreateObject("java", "flex.data.DataServiceTransaction");
t = dst.getCurrentDataServiceTransaction();
isRefill = t.isRefill();
</cfscript>
This does not work over RMI when ColdFusion and Flex are not in the same web application.
685
This count method calls a different count method in the DAO CFC, which contains the following essential elements,
without any error handling:
686
Authentication
To authenticate users when using the LiveCycle Data Services ES assembler, you use the Flex
setRemoteCredentials() method on the DataService object. The credentials, which are in the FlexSession object,
are passed to the ColdFusion application, where you can use the cflogin tag to perform authentication. Alternatively,
you can set credentials in the Flex destination, although it is not the recommended way to do so.
You can set the credentials by doing either of the following:
687
<destination id="cfcontact">
<adapter ref="coldfusion-dao" />
<channels>
<channel ref="cf-dataservice-rtmp" />
</channels>
<properties>
<source>samples.contact.ContactAssembler</source>
<scope>application</scope>
<remote-username>wilsont</remote-username>
<remote-password>password</remote-password>
...
/properties>
</destination>
Enabling SSL
You encrypt communication between ColdFusion and Flex by enabling Secure Sockets Layer (SSL). Enabling SSL only
makes sense if you are running LiveCycle Data Services ES remotely. To use SSL, create a keystore file. The keystore is
a self-signed certificate. (You do not require a certificate signed by a Certificate Authority, although if you do use one,
you do not have to configure Flex as indicated in the following steps.) The information in the keystore is encrypted
and can be accessed only with the password that you specify. To create the keystore, you use the Java keytool utility,
which is included in your Java Runtime Environment (JRE).
To enable SSL, you do the following:
1 Create the keystore
2 Configure Flex
3 Enable SSL in the ColdFusion Administrator
The following table describes the parameters of the keytool utility that you use:
Parameter
Description
-alias
The name of the keystore entry. You can use any name as long as you are consistent when referring to it.
-dname
The Distinguished Name, which contains the Common Name (cn) of the server.
-keystore
-keypass
-storepass
The password for the keystore. The encrypted storepass is stored in ColdFusion configuration files.
-rfc
-file
-v
Next, you place the certificate that you created in the file that the JVM uses to decide what certificates to trust. The file
in which you place the certificate (usually named cacerts), is located in the JRE, under the lib/security folder.
688
Configure Flex
1 Export the keystore to a certificate by using the keytool utility, with a command like the following:
keytool -export -v -alias FlexAssembler -keystore cf.keystore -rfc -file cf.cer
2 Import the certificate into the JRE cacerts file for your server by using the keytool utility, with a command like the
following:
keytool -import -v -alias FlexAssembler -file cf.cer -keystore
C:\fds2\UninstallerData\jre\lib\security\cacerts
The previous example specifies the location of the keystore for LiveCycle Data Services ES with integrated JRun,
installed using the default settings. If you are using a different server, specify the location of the cacerts file for the
JRE that you are using. For example, if you are using JBoss, you specify the keystore location as
$JAVA_HOME/jre/lib/security/cacerts.
If you specify an invalid keystore file or password, ColdFusion does not enable SSL, and disables Flex Data
Management Support.
Data translation
The following table lists the ColdFusion data types and the corresponding Adobe Flash or ActionScript data type:
ColdFusion data type
String
String
Array
[] = Array
Struct
{} = untyped Object
Query
ArrayCollection
CFC
Class = typed Object (if a matching ActionScript class exists, otherwise the CFC becomes a
generic untyped Object (map) in ActionScript)
CFC Date
ActionScript Date
CFC String
ActionScript String
CFC Numeric
ActionScript Numeric
689
Note: Client-side ActionScript does not support the two new server-side ActionScript functions, CF.query and CF.http.
Server-side requirements
Creating ActionScript that executes on the server helps leverage your knowledge of ActionScript. It also provides direct
access to ColdFusion query and HTTP features. The CF.query and CF.http ActionScript functions let you perform
ColdFusion HTTP and query operations.
690
Note: On the server side, ActionScript files use the extension .asr.
For example, the following server-side ActionScript code builds on the client-side code shown previously:
// Filename: stockquotes.asr
// Here is the getQuotes method invoked in the client-side ActionScript.
// It accepts a single stock quote symbol argument.
function getQuotes(symbol)
{
// Query some provider for the specified stock quote and return the
// results. In this case, the getQuotesFromProvider method is
// defined elsewhere in this ActionScript code.
data = getQuotesFromProvider(symbol);
// Return the data to the client.
// Note: this example does not include any of the error checking
// logic you would normally use prior to returning the data.
return data;
}
The getQuotes function conducts the stock quote request and returns the results of the request to the client as a
RecordSet object.
Software requirements
To use server-side ActionScript files, you must have the following software installed:
Adobe Flash
ColdFusion
Flash Remoting Components
For more information about these products, go to www.adobe.com.
You can also point to virtual mappings, such as cfsuite.asr.stock.stockquotes where cfsuite is a virtual
mapping and asr.stock is subdirectories of that mapping.
Benefits
Server-side ActionScript lets your ActionScript engineers use their knowledge of ActionScript to write code for the
back end of their SWF files, which can mean more meaningful levels of interactivity for your users. Your SWF files can
share a library of server-side ActionScript functions, which means you can define functions that are tailored to your
own business.
You could, for example, create a server-side ActionScript file that defines a whole library of SQL query methods. With
these query methods defined on the server side, your Flash designers only have to run the specific query function they
want to return data to their SWF movies. They do not have to write any SQL, and they do not have to create a query
every time they retrieve data from a ColdFusion data source. It is a way of creating reusable queries that your entire
Flash design team can use.
691
Coding the ColdFusion query and HTTP operations in ActionScript is very straightforward. The CF.query and
CF.http functions provide a well-defined interface for building SQL queries and HTTP operations.
For example, the following is a typical server-side ActionScript function definition that returns query data:
// This function shows a basic CF.query operation using only
// arguments for data source name and for SQL.
function basicQuery()
{
mydata = CF.query({datasource:"customers",
sql:"SELECT * FROM myTable"});
return mydata;
}
What to do next
If you are already familiar with ActionScript, here a few things to get you started:
How to establish a connection with the Flash Remoting service using client-side ActionScript. See Connecting to
the Flash Remoting service on page 691
How to reference server-side ActionScript functions and methods. See Using server-side ActionScript functions
on page 692.
How to code the server-side CF.query and CF.http functions. See Using the CF.query function on page 694 and
Using the CF.http function on page 700. Also see the reference pages for these functions in the CFML Reference.
For additional information on using Flash Remoting, see Using the Flash Remoting Service on page 606 and Using
Flash Remoting.
functions.
a Use the following command to include the NetServices class:
#include "NetServices.as"
For more information about the NetDebug and RecordSet classes, see Using Flash Remoting.
2 Since the Flash Remoting service serves as a broker for calls to server-side ActionScript functions, identify the Flash
Specify a server host name. The default port number for the Flash Remoting service is 8500.
3 Create the gateway connection using the NetServices.createGatewayConnection function; for example:
gatewayConnection = NetServices.createGatewayConnection();
692
Call a function
1 Create an instance of the server-side ActionScript file using the getService function. This function instantiates
the server-side ActionScript file as an object to use on the client side. For example:
albumService = gatewayConnection.getService("recordsettest", this)
Where recordsettest represents the name of the server-side ActionScript file, without the filename extension
.asr.
2 Call a function defined in your server-side ActionScript object. Use dot notation to specify the object name followed
Where albumService is the instance of the server-side ActionScript file and getAlbum is a function that passes two
arguments, "The Color and The Shape" and "1999".
Note: Arguments must occur in the order defined in the function declaration.
3 Handle the function results in ActionScript. See Using the function results in ActionScript on page 692.
The CF.query function returns a record set, which you manipulate using methods available in the RecordSet
ActionScript class object. See Using results returned by the CF.query function section.
The CF.http function returns simple text strings through properties that you reference in your server-side
ActionScript. See Using results returned by the CF.http function section.
Using results returned by the CF.query function
You use functions in the RecordSet ActionScript object to access the data returned in a CF.query record set; for
example, how many records are in the record set and the names of the columns. You can also use the RecordSet
functions to pull the query data out of the record set. To do so, you reference a specific row number in the record set
and use the getItemAt RecordSet function, as in the following example:
// This function populates a Flash text box with data in the first row
// of the record set under the "email" column name.
function selectData_Result ( result )
{
stringOutput.text = result.getItemAt(0)["email"];
_root.employeesView.setDataProvider(result);
}
In the example, the column name is referenced in the getItemAt function between square brackets [ ]. (In
ActionScript, indexes start at 0, so getItemAt(0) returns the first row.)
693
For more information, see Using the CF.query function on page 694.
Using results returned by the CF.http function
The CF.http server-side ActionScript function returns data as simple text. You write server-side functions that
reference the properties available in the object returned by the CF.http function. These properties store the file
content of the retrieved file, HTTP status codes, the MIME type of the returned file, and so on. On the client side, you
create return functions to handle data returned by the CF.http function. You write these functions to handle simple
text data.
For more information, see Using the CF.http function on page 700.
Type
Description
config
Global
application
Global
The context for the current web application. The context defines methods that provide, for
example, the MIME type of a file that can be used to write to a log file. There is one context per
web application.
Class: javax.servlet.ServletContext
request
Request
An object containing client request information. The object provides data, including
parameter name and values, attributes, and an input stream.
Class: HttpServletRequest (subtype of javax.servlet.ServletRequest)
response
Request
For more information about these scope objects, see the documentation on the javax.servlet class at
http://java.sun.com.
Pull data into your SWF movie from a ColdFusion data source
1 Create a server-side ActionScript file that performs queries against a ColdFusion data source.
2 Write ActionScript code in your SWF movie that references your ActionScript file (.asr) on the ColdFusion server.
You create server-side ActionScript to execute the query and return the data in a record set to the clientyour SWF
movie. You can use methods in the RecordSet ActionScript object on the client to manipulate data in the record set
and present data in your SWF movie.
Note: Client-side ActionScript files use the .as extension. Server-side ActionScript files use the .asr (ActionScript remote)
extension.
694
Create database queries in the server-side ActionScript file using the CF.query ActionScript function. See Using
the CF.query function on page 694.
Reference the server-side ActionScript file in your SWF movie. See Connecting to the Flash Remoting service on
page 691.
Using the CF.query function, you can do the following tasks:
Create user login interfaces that validate users against a ColdFusion data source.
Populate form elements and data grids with data from a ColdFusion data source.
Create banners that pull data (such as URLs or image file paths) out of a database.
The CF.query function can retrieve data from any supported ColdFusion data source (see About ColdFusion data
sources on page 694).
695
Note: The named argument style requires curly brackets {} to surround the function arguments.
Using CF.query positional argument syntax
Positional arguments support a subset of CF.query arguments, and you can create more efficient code. The following
is the syntax for the positional argument style:
// CF.query positional argument syntax
CF.query(datasource, sql);
CF.query(datasource, sql, maxrows);
CF.query(datasource, sql, username, password);
CF.query(datasource, sql, username, password, maxrows);
Note: When using positional arguments, do not use curly braces {}.
Description
addItem
addItemAt
addView
filter
Creates a RecordSet object that contains selected records from the original RecordSet object
getColumnNames
getItemAt
getItemID
696
Method
Description
getLength
getNumberAvailable
Returns the number of records that have been downloaded from the server
isFullyPopulated
isLocal
removeAll
removeItemAt
replaceItemAt
setDeliveryMode
setField
sort
sortItemsBy
These functions are available for every RecordSet object returned by the CF.query function to the Flash client. You
run these functions as follows:
objectName.functionName();
For example, in the result function that you create to handle record set data returned by the CF.query function, you
can reference the database column names returned in the record set using the getColumnNames RecordSet function:
function selectData_Result ( result )
{
//result holds the query data; employeesView is a Flash list box
stringOutput.text = result.getColumnNames();
_root.employeesView.setDataProvider(result);
}
A server-side ActionScript file named personneldirectory.asr that includes functions that interact with a
ColdFusion data source.
Remoting service.
2 Create the SWF movie interface. See Creating the SWF movie interface on page 697.
697
3 Define a search function that sends user data to the Flash Remoting service. See Submitting user data to the Flash
698
#include "NetServices.as"
function search()
{
// The search() method is defined in the server-side AS file
directoryService.search(firstName.text, lastName.text);
dataView.setDataProvider(null);
status.text = "waiting...";
}
Description
directoryService.search
Passes the contents of the firstName and lastName text boxes to server-side
ActionScript.
(firstName.text, lastName.text);
dataView.setDataProvider
(null);
Displays a message in the status text box while the record set is being
retrieved from server-side ActionScript.
status.text = "waiting...";
Description
function search_Result
The _Result suffix tells the Flash Remoting service to return the results of
the search function to this function.
(resultset)
dataView.setDataProvider
(resultset);
status.text = (0+resultset.
Assigns the results returned by the Flash Remoting service to the dataView
list box.
Displays the number of records returned by the Flash Remoting service.
699
In this example, the inited variable is evaluated for a value. If inited is null (not connected), the movie connects to
the Flash Remoting service using the NetServices object. For more information about connecting to the Flash
Remoting service, see Connecting to the Flash Remoting service on page 691.
Using the Get method, you send information to the remote server directly in the URL. This method is common for
a one-way transaction in which the CF.http function retrieves an object, such as the contents of a web page.
The Post method can pass variables to a form or CGI program, and can also create HTTP cookies.
The most basic way to use the CF.http function is to use it with the Get method argument to retrieve a page from a
specified URL. The Get method is the default for the CF.http function.
The following server-side example retrieves file content from the specified URL:
function basicGet(url)
{
// Invoke with just the url argument. This is an HTTP GET.
result = CF.http(url);
return result.get("Filecontent");
}
700
Description
Text
A Boolean value indicating whether the specified URL location contains text data.
Charset
Header
Filecontent
Mimetype
MIME type. Examples of MIME types include text/html, image/png, image/gif, video/mpeg, text/css, and
audio/basic.
responseHeader
Response header. If there is one instance of a header key, this value can be accessed as a simple type. If there is
more than one instance, values are put in an array in the responseHeader structure.
Statuscode
HTTP error code and associated error string. Common HTTP status codes returned in the response header include
the following:
400: Bad Request
401: Unauthorized
403: Forbidden
404: Not Found
405: Method Not Allowed
701
Parameter
Description
name
type
Transaction type:
value
URL
FormField
Cookie
CGI
File
Value of URL, FormField, Cookie, File, or CGI variables that are passed
In the following example, the CF.http function passes HTTP Post parameters in an array of objects:
function postWithParamsAndUser()
{
// Set up the array of Post parameters. These are just like cfhttpparam tags.
params = new Array();
params[1] = {name:"arg2", type:"URL", value:"value2"};
url = "http://localhost:8500/";
// Invoke with the method, url, params, username, and password
result = CF.http("post", url, params, "karl", "salsa");
return result.get("Filecontent");
}
702
For more information about CF.http function properties, see CF.http in the CFML Reference.
703
cfapplet
cfform
cfinput
cfselect
cftextarea
These tags support all the attributes of their HTML counterparts, plus ColdFusion attributes and features.
ColdFusion also provides the following forms tags that have no direct equivalent in HTML:
required, contains a specific type of data, has a maximum length, or is in a range of values. You can also use data
masking to control user input. For more information on validation, see Validating Data on page 743.
Note: ColdFusion also provides a method of doing on-server validation of HTML form controls.
Flash format forms and elements You can display a form as Flash, which works identically on a variety of platforms
and provides additional display features not available in HTML. These features include accordion-style and multipletab form panes and automatic element positioning. You can also display cftree, cfgrid, and cfcalendar form
704
elements as Flash items in an otherwise-HTML form. For more information on Flash forms and form elements, see
Creating Forms in Flash on page 765.
XML Skinable forms ColdFusion can generate XML forms and apply XSLT skins to format the forms. XML format
forms let you separate the form presentation from the form logic and data field information. They give you detailed
control over the appearance of the forms by applying custom skins, and let you create custom controls. For more
information on XML skinnable forms, see Creating Skinnable XML Forms on page 783.
Direct support for ColdFusion variables You can easily use ColdFusion variables directly to populate your form
controls. For example, you can specify a query result to populate the cfgrid and cftree tags.
These features make CFML forms tags powerful and flexible, and let you easily develop fully featured, pleasing forms.
The CFML tags used here, do not describe or use most of their special features. SeeBuilding Dynamic Forms with
cfform Tags on page 722 for information on how to use many of the tags that are specific to ColdFusion, such as
cftree and cfgrid.
Code
Text control
<cfselect name="ControlName">
<option value="Value1">DisplayName1
<option value="Value2">DisplayName2
<option value="Value3">DisplayName3
</cfselect>
Radio buttons
705
Control
Code
Check box
Reset button
Submit button
The following listing shows the form source in detail. To test the form and use it as input for later examples, save this
code as formpage.cfm.
<html>
<head>
<title>Input form</title>
</head>
<body>
<!--- Specify the action page in the form tag. The form variables will
pass to this page when the form is submitted. --->
<cfform action="actionpage.cfm" method="post">
<!--- Text box. --->
<p>
First Name: <cfinput type="Text" name="FirstName" size="20"maxlength="35"><br>
Last Name: <cfinput type="Text" name="LastName" size="20" maxlength="35"><br>
Salary: <cfinput type="Text" name="Salary" size="10" maxlength="10">
</p>
<!--- List box. --->
<p>
City
<cfselect name="City">
<option value="Arlington">Arlington
<option value="Boston">Boston
<option value="Cambridge">Cambridge
<option value="Minneapolis">Minneapolis
<option value="Seattle">Seattle
</cfselect>
</p>
<!--- Radio buttons. --->
<p>
Department:<br>
706
Forms guidelines
When using forms, keep in mind the following guidelines:
To make the coding process easy to follow, name form controls the same as target database fields. For example, if
a text control corresponds to a data source FirstName field, use FirstName as the control name.
For ease of use, limit radio buttons to between three and five mutually exclusive options. If you need more options,
consider a drop-down list.
Use list boxes to allow the user to choose from many options or to choose multiple items from a list.
Check boxes, radio buttons, and list boxes do not pass data to action pages unless they are selected on a form. If you
try to reference these variables on the action page, you receive an error if they are not present. For information on
how to determine whether a variable exists on the action page, see Testing for a variables existence on page 709.
You can dynamically populate drop-down lists using query data. For more information, see Dynamically
populating list boxes on page 718.
707
On the action page, the form variables are in the Form scope, prefix them with Form. to explicitly tell ColdFusion
that you are referring to a form variable. For example, the following code references the LastName form variable for
output on an action page:
<cfoutput>
#Form.LastName#
</cfoutput>
The Form scope also contains a list variable called Form.fieldnames. It contains a list of all form variables submitted
to the action page. If no form variables are passed to the action page, ColdFusion does not create the
Form.fieldnames list.
When you want to return information about employees that matches user search criteria, you use the SQL WHERE
clause with a SQL SELECT statement. When the WHERE clause is processed, it filters the query data based on the
results of the comparison.
For example, to return employee data for only employees with the last name of Smith, you build a query that looks like
the following:
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT FirstName, LastName, Contract
FROM Employee
WHERE LastName = 'Smith'
</cfquery>
However, instead of placing the LastName directly in the SQL WHERE clause, you can use the text that the user
entered in the form for comparison:
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary
FROM Employee
WHERE LastName=<cfqueryparam value="#Form.LastName#"
CFSQLType="CF_SQL_VARCHAR">
</cfquery>
For security, this example encapsulates the form variable within the cfqueryparam tag to ensure that the user passed
a valid string value for the LastName. For more information on using the cfqueryparam tag with queries and on
dynamic SQL, see Accessing and Retrieving Data on page 410.
708
<html>
<head>
<title>Retrieving Employee Data Based on Criteria from Form</title>
</head>
<body>
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary
FROM Employee
WHERE LastName=<cfqueryparam value="#Form.LastName#"
CFSQLType="CF_SQL_VARCHAR">
</cfquery>
<h4>Employee Data Based on Criteria from Form</h4>
<cfoutput query="GetEmployees">
#FirstName#
#LastName#
#Salary#<br>
</cfoutput>
<br>
<cfoutput>Contractor: #Form.Contractor#</cfoutput>
</body>
</html>
The browser displays a line with the first and last name and salary for each entry in the database that match the
name you typed, followed by a line with the text Contractor: Yes.
5 Click Back in your browser to redisplay the form.
6 Remove the check mark from the check box and submit the form again.
This time an error occurs because the check box does not pass a variable to the action page. For information on
modifying the actionpage.cfm page to fix the error, see Testing for a variables existence on page 709.
Reviewing the code
The following table describes the highlighted code and its function:
Code
Description
<cfquery
name="GetEmployees"datasource="cfdocexamples">
formpage.cfm.
<cfoutput query="GetEmployees">
709
Code
Description
#FirstName#
#LastName#
#Salary#<br>
Displays the value of the FirstName, LastName, and Salary fields for a
record, starting with the first record, then goes to the next line. Keeps
displaying the records that match the criteria you specified in the
SELECT statement, followed by a line break, until you run out of
records.
</cfoutput>
<br>
<cfoutput>Contractor: #Form.Contractor#
</cfoutput>
Displays a blank line followed by the text Contractor: and the value
of the form Contractor check box.
A more complete example would test to ensure the existence of the
variable and would use the variable in the query.
The argument passed to the IsDefined function must always be enclosed in double-quotation marks. For more
information on the IsDefined function, see the CFML Reference.
If you attempt to evaluate a variable that you did not define, ColdFusion cannot process the page and displays an error
message. To help diagnose such problems, turn on debugging in the ColdFusion Administrator. The Administrator
debugging information shows which variables are being passed to your application pages.
Use the required attribute of the cfinput, cfselect, cftextarea, and cftree tags.
Use a hidden field that has a name attribute composed of the field name and the suffix _required. You can use this
technique with CFML and HTML form tags.
For example, to require that the user enter a value in the FirstName field of a cfinput tag, use the following syntax:
<cfinput type="Text" name="FirstName" size="20" maxlength="35" required="Yes">
To require that the user enters a value in the FirstName field of an HTML input tag, use the following syntax:
<input type="Text" name="FirstName" size="20" maxlength="35">
<input type="hidden" name="FirstName_required">
In either of these examples, if the user leaves the FirstName field empty, ColdFusion rejects the form submittal and
returns a message informing the user that the field is required. You can customize the contents of this error message.
If you use a required attribute, you customize the message by using the message attribute, as follows:
710
If you use a hidden field tag, you customize the message using the value attribute of the hidden field, as follows:
<input type="hidden" name="FirstName_required"
value="You must enter your first name.">
A form variable is available on the action page and pages that it includes.
Prefix form variables with "Form."when referencing them on the action page.
Surround variable values with number signs (#) for output.
Variables for check boxes, radio buttons, and list boxes with size attributes greater than 1 only get passed to the
action page if you select an option. Text boxes, passwords, and text area fields pass an empty string if you do not
enter text.
An error occurs if the action page tries to use a variable that was not passed.
If multiple controls have the same name, one form variable is passed to the action page with a comma-delimited
list of values.
You can validate form variable values on the client or the server.
711
<html>
<head>
<title>Retrieving Employee Data Based on Criteria from Form</title>
</head>
<body>
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary
FROM Employee
WHERE LastName=<cfqueryparam value="#Form.LastName#"
CFSQLType="CF_SQL_VARCHAR">
</cfquery>
<h4>Employee Data Based on Criteria from Form</h4>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Salary</th>
</tr>
<cfoutput query="GetEmployees">
<tr>
<td>#FirstName#</td>
<td>#LastName#</td>
<td>#Salary#</td>
</tr>
</cfoutput>
</table>
<br>
<cfif IsDefined("Form.Contractor")>
<cfoutput>Contractor: #Form.Contractor#</cfoutput>
</cfif>
</body>
</html>
The records that match the criteria specified in the form appear in a table.
Reviewing the code
The following table describes the highlighted code and its function:
Code
Description
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Salary</th>
</tr>
In the first row of the table, includes three columns, with the headings: First Name,
Last Name, and Salary.
<cfoutput query="GetEmployees">
712
Code
Description
<tr>
<td>#FirstName#</td>
<td>#LastName#</td>
<td>#Salary#</td>
</tr>
For each record in the query, creates a row in the table, with three columns that
display the values of the FirstName, LastName, and Salary fields of the record.
</cfoutput>
</table>
to
<td>#DollarFormat(Salary)#</td>
713
<html>
<head>
<title>Retrieving Employee Data Based on Criteria from Form</title>
</head>
<body>
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT Departmt.Dept_Name,
Employee.FirstName,
Employee.LastName,
Employee.StartDate,
Employee.Salary
FROM Departmt, Employee
WHERE Departmt.Dept_ID = Employee.Dept_ID
<cfif IsDefined("Form.Department")>
AND Departmt.Dept_Name=<cfqueryparam value="#Form.Department#"
CFSQLType="CF_SQL_VARCHAR">
</cfif>
<cfif Form.LastName IS NOT "">
AND Employee.LastName=<cfqueryparam value="#Form.LastName#"
CFSQLType="CF_SQL_VARCHAR">
</cfif>
</cfquery>
<h4>Employee Data Based on Criteria from Form</h4>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Salary</th>
</tr>
<cfoutput query="GetEmployees">
<tr>
<td>#FirstName#</td>
<td>#LastName#</td>
<td>#Salary#</td>
</tr>
</cfoutput>
</table>
</body>
</html>
714
Code
Description
SELECT Departmt.Dept_Name,
Employee.FirstName,
Employee.LastName,
Employee.StartDate,
Employee.Salary
FROM Departmt, Employee
WHERE Departmt.Dept_ID = Employee.Dept_ID
Retrieves the fields listed from the Departmt and Employee tables, joining the
tables based on the Dept_ID field in each table.
<cfif IsDefined("Form.Department")>
AND Departmt.Dept_Name=<cfqueryparam
value="#Form.Department#"
CFSQLType="CF_SQL_VARCHAR">
</cfif>
If the user specified a department on the form, only retrieves records where the
department name is the same as the one that the user specified. Use number signs
(#) in the SQL AND statement to identify Form.Department as a ColdFusion
variable, but not in the IsDefined function.
If the user specified a last name in the form, only retrieves the records in which the
last name is the same as the one that the user entered in the form.
Do the following:
715
<html>
<head>
<title>Retrieving Employee Data Based on Criteria from Form</title>
</head>
<body>
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT Departmt.Dept_Name,
Employee.FirstName,
Employee.LastName,
Employee.StartDate,
Employee.Salary
FROM Departmt, Employee
WHERE Departmt.Dept_ID = Employee.Dept_ID
<cfif isdefined("Form.Department")>
AND Departmt.Dept_Name = <cfqueryparam value="#Form.Department#"
CFSQLType="CF_SQL_VARCHAR">
</cfif>
<cfif Form.LastName is not "">
AND Employee.LastName = <cfqueryparam value="#Form.LastName#"
CFSQLType="CF_SQL_VARCHAR">
</cfif>
</cfquery>
<cfif GetEmployees.recordcount is "0">
No records match your search criteria. <br>
Please go back to the form and try again.
<cfelse>
<h4>Employee Data Based on Criteria from Form</h4>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Salary</th>
</tr>
<cfoutput query="GetEmployees">
<tr>
<td>#FirstName#</td>
<td>#LastName#</td>
<td>#Salary#</td>
</tr>
</cfoutput>
</cfif>
</table>
</body>
</html>
716
Using any of the following tags or functions on a page anywhere after the cfflush tag can cause errors or
unexpected results: cfcontent, cfcookie, cfform, cfheader, cfhtmlhead, cflocation, and SetLocale. (These
tags and functions normally modify the HTML header, but cannot do so after a cfflush tag, because the cfflush
tag sends the header.)
Using the cfset tag to set a cookie anywhere on a page that has a cfflush tag does not set the cookie in the browser.
Using the cfflush tag within the body of several tags, including cfsavecontent, cfqueryparam, and custom tags,
can cause errors.
If you save Client variables as cookies, any client variables that you set after a cfflush tag are not saved in the
browser.
You can catch cfflush errors, except Cookie errors, with a cfcatch tag. Catch cookie errors with a cfcatch
type="Any" tag.
717
<html>
<head>
<title>Your Magic numbers</title>
</head>
<body>
<h1>Your Magic numbers</h1>
<P>It will take us a little while to calculate your ten magic numbers.
It takes a lot of work to find numbers that truly fit your personality.
So relax for a minute or so while we do the hard work for you.</P>
<h2>We are sure you will agree it was worth the short wait!</h2>
<cfflush>
<cfflush interval=10>
<!--- Delay Loop to make is seem harder. --->
<cfloop index="randomindex" from="1" to="200000" step="1">
<cfset random=rand()>
</cfloop>
<!--- Now slowly output 10 random numbers. --->
<cfloop index="Myindex" from="1" to="10" step="1">
<cfloop index="randomindex" from="1" to="100000" step="1">
<cfset random=rand()>
</cfloop>
<cfoutput>
Magic number #Myindex# is: #RandRange(
100000, 999999)#<br><br>
</cfoutput>
</cfloop>
</body>
</html>
Description
<h2>We are sure you will agree it was worth the short
wait!</h2>
<cfflush>
Sends the HTML header and all HTML output to the cfflush tag to the
user. This displays the explanatory paragraph and H2 tag contents.
<cfflush interval=10>
718
Use the cfquery tag to retrieve the column data from a database table.
Use the cfselect tag with the query attribute to dynamically populate the options of this form control.
719
Department:<br>
<cfinput type="radio"
<cfinput type="radio"
<cfinput type="radio"
<cfinput type="radio"
</p>
name="Department"
name="Department"
name="Department"
name="Department"
value="Training">Training<br>
value="Sales">Sales<br>
value="Marketing">Marketing<br>
value="HR">HR<br>
Description
<cfquery name="GetDepartments"
datasource="cfdocexamples">
SELECT DISTINCT Location
FROM Departmt
</cfquery>
720
Note: If the user does not select a check box or make a selection from a list box, no variable is created. The cfinput and
cfupdate tags do not work correctly if there are no values. To prevent errors, make the form fields required, use dynamic
SQL, or use the cfparam tag to set a default value for the form field.
Check boxes
When you place a series of check boxes with the same name in a form, the variable that is created contains a commadelimited list of values. The values can be either numeric values or alphanumeric strings. These two types of values are
treated slightly differently.
Handling numeric values
Suppose you want a user to select one or more departments using check boxes. You then query the database to retrieve
detailed information on the selected departments. The code for a simple set of check boxes that lets the user select
departments looks like the following:
<cfinput type="checkbox"
name="SelectedDepts"
value="1">
Training<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="2">
Marketing<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="3">
HR<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="4">
Sales<br>
</html>
The user sees the name of the department, but the value attribute of each check box is a number that corresponds to
the underlying database primary key for the departments record.
If the user checks the Marketing and Sales items, the value of the SelectedDepts form field is 2,4 and you use the
SelectedDepts value in the following SQL statement:
SELECT *
FROM Departmt
WHERE Dept_ID IN ( #Form.SelectedDepts# )
721
The first example searched for department information based on a numeric primary key field called Dept_ID.
Suppose, instead, that the primary key is a database field called Dept_Name that contains string values. In that case,
your code for check boxes should look like the following:
<cfinput type="checkbox"
name="SelectedDepts"
value="Training">
Training<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="Marketing">
Marketing<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="HR">
HR<br>
<cfinput type="checkbox"
name="SelectedDepts"
value="Sales">
Sales<br>
If the user checked Marketing and Sales, the value of the SelectedDepts form field would be the list Marketing,Sales
and you use the following SQL statement:
SELECT *
FROM Departmt
WHERE Dept_Name IN
(#ListQualify(Form.SelectedDepts,"'")#)
In SQL, all strings must be surrounded in single-quotation marks. The ListQualify function returns a list with the
specified qualifying character (here, a single-quotation mark) around each item in the list.
If you select the second and fourth check boxes in the form, the following statement gets sent to the database:
SELECT *
FROM Departmt
WHERE Dept_Name IN ('Marketing','Sales')
722
If the user selects the Marketing and Sales items, the value of the SelectDepts form field is 2,4. If this parameter is used
in the following SQL statement:
SELECT *
FROM Departmt
WHERE Dept_ID IN (#form.SelectDepts#)
If the user selects the Marketing and Sales items, the SelectDepts form field value is Marketing,Sales.
Just as you did when using check boxes to search database fields containing string values, use the ColdFusion
ListQualify function with multiple-selection list boxes:
SELECT *
FROM Departmt
WHERE Dept_Name IN (#ListQualify(Form.SelectDepts,"'")#)
723
as grids, trees, and calendars. HTML lets you present a familiar appearance, but does not let you easily separate data
and presentation, or provide some of the more complex structures, such as Flash tabbed navigators or accordions, or
customized XML controls.
Flash Presents a modern, visually pleasing appearance. Flash format supports several controls, such as tabbed
navigators and accordions, that are not available in HTML. Flash forms are also browser-independent. In Flash format,
Flash Player works in all commonly used browsers on Windows and Macintosh systems, and in Netscape and Mozilla
on Linux.
XML Lets you specify an Extensible Stylesheet Language Transformation (XSLT) skin that converts the XML into
styled HTML output. Adobe ColdFusion provides several skins that you can use, and you can write your own custom
skins and support custom controls.
The cfform tag and its subtags also provide you with several methods for validating input data. For example, you can
perform the validation on the browser or on the server. You can check the data type, or you can mask data input.
Individual cfform tags have additional dynamic features. Several of the tags do not have HTML counterparts, and
others directly support dynamically populating the control from data sources. Also, the cfform tag preservedata
attribute retains user input in a form after the user submits the form, so the data reappears if the form gets redisplayed.
The information here describes features of the cfform tag and focuses on using several of the cfform child tags that
do not have HTML counterparts. For other features of ColdFusion forms that you create using the cfform tag, see the
following:
Description
cfapplet
Embeds a custom Java applet in the form. Not supported in Flash format Embedding Java applets on page 741.
forms.
cfcalendar
Displays an interactive Flash calendar that can be included in an HTML The cfcalendar tag in the CFML Reference
or Flash format form. ignored in XML skinable forms. The calendar lets a
user select a date for submission as a form variable.
cfform
Creates a container control for organizing and formatting multiple form Creating Forms in Flash on page 765,
controls. Used in the cfform tag body of Flash and XML skinable forms. Creating Skinnable XML Forms on
page 783
Ignored in HTML forms.
cfformitem
Inserts a horizontal line, a vertical line, or formatted or unformatted text Creating Forms in Flash on page 765,
in a Flash form. Used in the cfform or cfformgroup tag body for Flash Creating Skinnable XML Forms on
page 783
and XML forms. Ignored in HTML forms.
cfgrid
Creates a Java applet or Flash data grid that you can populate from a
query or by defining the contents of individual cells. You can also use
grids to insert, update, and delete records from a data source.
724
Control
Description
cfinput
Equivalent to the HTML input tag, with the addition of input validation. Creating a basic form on page 704
cfselect
Displays a selection box. Equivalent to the HTML select tag, with the
addition of input validation.
cfslider
Creates a Java applet-based control that lets users enter data by moving Building slider bar controls on page 732
a slider. Not supported in Flash format forms.
cftextarea
Displays a text input area. Equivalent to the HTML textarea tag, with
the addition of input validation.
cftree
In the cftree tag, the preservedata attribute causes the tree to expand to the previously selected element. For this
to work correctly, set the completePath attribute to True.
The preservedata attribute has no effect on a cfgrid tag. If you populate the control from a query, update the
data source with the new data (typically by using a cfgridupdate tag) before redisplaying the grid. The grid then
displays the updated database information.
Browser considerations
The applet-based versions of the cfgrid, cfslider, and cftree forms use JavaScript and Java to display their
content. To allow them to display consistently across a variety of browsers, these applets use the Java plug-in. As a
result, they are independent of the level of Java support provided by the browser.
ColdFusion downloads and installs the browser plug-in if necessary. Some browsers display a single permission dialog
box asking you to confirm the plug-in installation. Other browsers, like older versions of Netscape, require you to
navigate some simple option windows.
725
Because the controls use JavaScript to return data to ColdFusion, if you disable JavaScript in your browser, it cannot
properly run forms that contain these controls. In that case, the controls still display, but data return and validation
does not work and you can receive a JavaScript error.
Because Java is handled by the plug-in and not directly by the browser, disabling Java execution in the browser does
not affect the operation of the controls. If for some other reason, however, the browser is unable to render the controls
as requested, a "not supported" message appears in place of the control.
You can use the cfform tags notsupported attribute to specify an alternative error message.
You can avoid browser Java and JavaScript issues with the cfgrid and cftree controls by using the Flash format
versions of these controls. These controls work on Windows, Mac OS X, and Linux, and do not rely on Java support.
There is no Flash version of the cfslider control, and there is no applet version of the cfcalendar control.
The different formats support different sets of features and attributes. The information here discusses general
techniques that apply to all three formats, and indicates any techniques that do not apply to a specific format. It uses
applet format for all examples, which use applet-specific attributes. For details on the features and attributes supported
in each format, see the cftree entry in the CFML Reference.
726
Description
<cftree name="tree1"
required="Yes"
hscroll="No"
Creates an item in the tree and puts the results of the query named engquery
in it. Because this tag uses a query, it puts one item on the tree per query
entry.
queryasroot="Yes"
Specifies the query name as the root level of the tree control.
img="folder,document"
Uses the folder and document images that ship with ColdFusion in the tree
structure.
When populating a cftree tag with data from a cfquery tag, you can specify
images or filenames for each level of the tree as a comma-separated list.
727
Description
ORDER BY Dept_ID
<cftreeitem value="Dept_ID,FullName"
Populates the tree with the department ID, and under each department, the full
name for each employee in the department.
queryasroot="Dept_ID"
img="computer,folder,document"
Uses the ColdFusion supplied computer image for the root level, folder image for the
department IDs, and document for the names, independent of whether any level is
expanded (open) or collapsed. The imgopen attribute has only two items, because
the employee names can never be open.
imgopen="computer,folder"
The cftreeitem comma-separated value, img, and imgopen attributes correspond to the tree level structure. In
applet format, if you omit the img attribute, ColdFusion uses the folder image for all levels in the tree; if you omit the
imgopen attribute, ColdFusion uses the folder image for all expanded levels in the tree. Flash format ignores the img
and imgopen attributes and always uses folders for levels with children and documents for nodes without children.
Form.treename.path Returns the complete path of the user selection, in the form:
[root]\node1\node2\node_n\value
The deptquery root does not appear in the path, because the cftree tag does not specify completePath="Yes". You
can specify the character used to delimit each element of the path form variable in the cftreedelimiter attribute.
The default is a backslash character (\).
Input validation
Although the cftree tag does not include a validate attribute, you can use the required attribute to force a user to
select an item from the tree control. In addition, you can use the onValidate attribute to specify your own JavaScript
code to perform validation.
728
729
730
computer
document
element
folder
floppy
fixed
remote
Note: In applet format, you can also control the tree appearance by using the cftree tag lookAndFeel attribute to
specify a Windows, Motif, or Metal look.
731
Code
Description
href="http://www.adobe.com">
href="http://www.adobe.com/devnet/mx/coldfu
sion/">
If the value attribute includes spaces, ColdFusion replaces the spaces with plus characters (+).
Automatically passing the name of the selected tree item as part of the URL makes it easy to implement a basic drill
down application that displays additional information based on the selection. For example, if the specified URL is
another ColdFusion page, it can access the selected value as the variable URL.CFTREEITEMKEY.
To disable this behavior, set the appendkey attribute in the cftree tag to no.
Populate a drop-down list box with query data using the cfselect tag
1 Create a ColdFusion page with the following content:
<cfquery name="getNames"
datasource="cfdocexamples">
SELECT * FROM Employee
</cfquery>
<cfform name="Form1" action="submit.cfm">
<cfselect name="employees"
query="getNames"
value="Emp_ID"
display="FirstName"
required="Yes"
multiple="Yes"
size="8">
</cfselect>
<br><input type="Submit" value="Submit">
</cfform>
732
Because the tag includes the multiple attribute, the user can select multiple entries in the list box. Also, because the
value tag specifies Emp_ID, the primary key for the Employee table, Employee IDs (not first names) get passed in the
Form.Employee variable to the application page specified in the cfformaction attribute.
You can use a query to create a two-level hierarchical list grouped by one of the query columns. For an example of this
use, see the example for the cfselect entry in the CFML Reference.
To get the value of the slider in the action page, use the variable Form.slider_name; in this case, Form.myslider.
733
Just as the cftree tag uses the cftreeitem tag, the cfgrid tag uses the cfgridcolumn and cfgridrow tags. You can
define a wide range of row and column formatting options, as well as a column name, data type, selection options, and
so on. You use the cfgridcolumn tag to define individual columns in the grid or associate a query column with a grid
column.
Use the cfgridrow tag to define a grid that does not use a query as the source for row data. If a query attribute is
specified in the cfgrid tag, the cfgridrow tags are ignored.
The cfgrid tag provides many attributes that control grid behavior and appearance. Only the most important of these
attributes are described here. For detailed information on these attributes, see the cfgrid tag in the CFML Reference.
Procedure
Double-click the column header to sort a column in ascending order. Double-click again to sort the
rows in descending order.
Rearranging columns
Click any column heading and drag the column to a new position.
When you click a cell (or row or column) that you cannot edit, its background color changes. The
default color is salmon pink.
Double-click the cell. Press Return when you finish entering the data.
Deleting a row
Click any cell in the row and click the Delete button. (Not available in Flash format grids.)
Inserting a row
Click the Insert button. An empty row appears at the bottom of the grid. To enter a value in each cell,
double-click the cell, enter the value, and click Return. (Not available in Flash format grids.)
Note: Use the cfgridcolumndisplay="No" attribute to hide columns that you want to include in the grid but not
expose to an end user. You typically use this attribute to include columns such as the tables primary key column in
the results returned by the cfgrid tag.
2 Save the file and view it in your browser.
734
Description
selectmode="single">
Allows the user to select only one cell; does not allow editing.
Other modes are row, column, and edit.
<cfgridcolumn name="Emp_ID">
<cfgridcolumn name="LastName">
<cfgridcolumn name="Dept_ID">
Create a page to which you pass the cfgrid form variables. In that page, perform cfquery operations to update
data source records based on the form values returned by the cfgrid tag.
Pass grid edits to a page that includes the cfgridupdate tag, which automatically extracts the form variable values
and passes that data directly to the data source.
Using the cfquery tag gives you complete control over interactions with your data source. The cfgridupdate tag
provides a much simpler interface for operations that do not require the same level of control.
Controlling cell contents
You can control the data that a user can enter into a cfgrid cell in the following ways:
By default, a cell is not editable. Use the cfgrid attribute selectmode="edit" to edit cell contents.
Use the cfgridcolumntype attribute to control sorting order, to make the fields check boxes, or to display an
image.
Use the cfgridcolumnvalues attribute to specify a drop-down list of values from which the user can choose. You
can use the valuesDisplay attribute to provide a list of items to display that differs from the actual values that you
enter in the database. You can use the valuesDelimiter attribute to specify the separator between values in the
valuesvaluesDisplay lists.
Although the cfgrid tag does not have a validate attribute, it does have an onValidate attribute that lets you
specify a JavaScript function to perform validation.
For more information on controlling the cell contents, see the attribute descriptions for the cfgridcolumn tag in the
CFML Reference.
735
Description
gridname.colname
Stores the new values of inserted, deleted, or updated cells. (Entries for deleted cells contain
empty strings.)
gridname.Original.colname
gridname.RowStatus.Action
Stores the type of change made to the grid rows: D for delete, I for insert, or U for update.
Note: The periods in these names are not structure separators; they are part of the text of the array name.
ColdFusion creates a gridname.colname array and a gridname.Original.colname array for each column in the grid. For
each inserted, deleted, or changed row in the grid, ColdFusion creates a row in each of these arrays.
For example, the following arrays are created if you update a cfgrid tag called mygrid that consists of two displayable
columns (col1, col2) and one hidden column (col3):
Form.mygrid.col1
Form.mygrid.col2
Form.mygrid.col3
Form.mygrid.original.col1
Form.mygrid.original.col2
Form.mygrid.original.col3
Form.mygrid.RowStatus.Action
The value of the array index increments for each row that is added, deleted, or changed, and does not indicate a grid
row number. All rows for a particular change have the same index in all arrays. Unchanged rows do not have entries
in the arrays.
If the user changes a single cell in col2, the following array elements contain the edit operation, the edited cell value,
and the original cell value:
Form.mygrid.RowStatus.Action[1]
Form.mygrid.col2[1]
Form.mygrid.original.col2[1]
If the user changes the values of the cells in col1 and col3 in one row and the cell in col2 in another row, the information
about the original and changed values is in the following array entries:
Form.mygrid.RowStatus.Action[1]
Form.mygrid.col1[1]
Form.mygrid.original.col1[1]
Form.mygrid.col3[1]
Form.mygrid.original.col3[1]
Form.mygrid.RowStatus.Action[2]
Form.mygrid.col2[2]
Form.mygrid.original.col2[2]
The remaining cells in the arrays (for example, Form.mygrid.col2[1] and Form.mygrid.original.col2[1]) have the
original, unchanged values.
736
737
Code
Description
<cfgrid name="employee_grid"
height=425
width=300
vspace=10
selectmode="edit"
query="empdata"
insert="Yes"
delete="Yes">
Populates a cfgrid control with data from the empdata query. Selecting a grid cell enables
you to edit it. You can insert and delete rows. The grid is 425 X 300 pixels and has 10 pixels
of space above and below it.
<cfgridcolumn name="Emp_ID"
header="Emp ID"
width=50
headeralign="center"
headerbold="Yes"
select="No">
Creates a 50-pixel wide column for the data in the Emp_ID column of the data source.
Centers a header named Emp ID and makes it bold.
<cfgridcolumn name="LastName"
header="Last Name"
width=100
headeralign="center"
headerbold="Yes">
Creates a 100-pixel wide column for the data in the LastName column of the data source.
Centers a header named Last Name and makes it bold.
<cfgridcolumn name="Dept_ID"
header="Dept"
width=35
headeralign="center"
headerbold="Yes">
Creates a 35-pixel wide column for the data in the Dept_ID column of the data source.
Centers a header named Dept and makes it bold.
Does not allow users to select fields in this column for editing. Since this field is the tables
primary key, users should not be able to change it for existing records, and the DBMS
should generate this field as an autoincrement value.
Updating stops when an error occurs. It is possible that some database changes are made, but the tag does not
provide any information on them.
738
<html>
<head>
<title>Update grid values</title>
</head>
<body>
<h3>Updating grid using cfgridupdate tag.</h3>
<cfgridupdate grid="employee_grid"
datasource="cfdocexamples"
tablename="Employee">
Click <a href="grid2.cfm">here</a> to display updated grid.
</body>
</html>
Note: To update a grid cell, modify the cell contents, and then press Return.
Reviewing the code
The following table describes the highlighted code and its function:
Code
Description
<cfgridupdate grid="employee_grid"
datasource="cfdocexamples"
tablename="Employee"
739
<html>
<head>
<title>Catch submitted grid values</title>
</head>
<body>
<h3>Grid values for Form.employee_grid row updates</h3>
<cfif isdefined("Form.employee_grid.rowstatus.action")>
<cfloop index = "counter" from = "1" to =
#arraylen(Form.employee_grid.rowstatus.action)#>
<cfoutput>
The row action for #counter# is:
#Form.employee_grid.rowstatus.action[counter]#
<br>
</cfoutput>
<cfif Form.employee_grid.rowstatus.action[counter] is "D">
<cfquery name="DeleteExistingEmployee"
datasource="cfdocexamples">
DELETE FROM Employee
WHERE Emp_ID=<cfqueryparam
value="#Form.employee_grid.original.Emp_ID[counter]#"
CFSQLType="CF_SQL_INTEGER" >
</cfquery>
<cfelseif Form.employee_grid.rowstatus.action[counter] is "U">
<cfquery name="UpdateExistingEmployee"
datasource="cfdocexamples">
UPDATE Employee
SET
LastName=<cfqueryparam
value="#Form.employee_grid.LastName[counter]#"
CFSQLType="CF_SQL_VARCHAR" >,
Dept_ID=<cfqueryparam
value="#Form.employee_grid.Dept_ID[counter]#"
CFSQLType="CF_SQL_INTEGER" >
WHERE Emp_ID=<cfqueryparam
value="#Form.employee_grid.original.Emp_ID[counter]#"
CFSQLType="CF_SQL_INTEGER">
</cfquery>
740
2 Rename your existing handle_grid.cfm file as handle_grid2.cfm to save it, and then save this file as
handle_grid.cfm.
3 View the grid2.cfm page in your browser, change the grid, and then submit them.
Description
<cfif isdefined("Form.employee_grid.rowstatus.action")>
<cfloop index = "counter" from = "1" to =
#arraylen(Form.employee_grid.rowstatus.action)#>
<cfoutput>
The row action for #counter# is:
#Form.employee_grid.rowstatus.action[counter]#
<br>
</cfoutput>
Displays the action code for this row: U for update, I for
insert, or D for delete.
741
Code
Description
</cfif>
</cfloop>
</cfif>
Return values: The cfapplet tag requires a form field name attribute, so you can avoid coding additional
JavaScript to capture the applets return values. You can reference return values like any other ColdFusion form
variable: Form.variablename.
Ease of use: The applets interface is defined in the ColdFusion Administrator, so each instance of the cfapplet
tag in your pages only needs to reference the applet name and specify a form variable name.
Parameter defaults: ColdFusion uses the parameter value pairs that you defined in the ColdFusion Administrator.
You can override these values by specifying parameter value pairs in the cfapplet tag.
When an applet is registered, you enter just the applet source and the form variable name:
<cfapplet appletsource="Calculator"name="calc_value">
By contrast, with the HTML applet tag, you must declare all the applets parameters every time you want to use it in
a ColdFusion page.
742
743
Not all Java applets return values. For instance, graphical widgets might not return a specific value. For this type of
applet, the method field in the ColdFusion Administrator remains empty, but you must still provide a cfappletname
attribute.
You can only use one method for each applet that you register. If an applet includes more than one method that you
want to access, you can register the applet with a unique name for each additional method you want to use.
Reference a Java applet return value in your application page
1 Specify the name of the method in the Add/Registered Java Applet page of the ColdFusion Administrator.
2 Specify the method name in the name attribute of the cfapplet tag.
When your page executes the applet, ColdFusion creates a form variable with the name that you specified. If you do
not specify a method, ColdFusion does not create a form variable.
Validating Data
You can validate data in Adobe ColdFusion, including form data, variable data and function parameters.
They let you provide feedback to users so that they can immediately correct information they provide. For example,
a form can provide immediate feedback when a user enters a name in a telephone number field, or the form could
force the user to enter the number in the correct format.
They help prevent application errors that can arise when processing invalid data. For example, a validation test can
prevent a variable that is used in a calculation from having nonnumeric data.
They can help enhance security by preventing malicious users from providing data that takes advantage of system
security weaknesses, such as buffer overrun attacks.
ColdFusion provides several techniques to ensure that data is valid. These include techniques for validating form data
and for validating ColdFusion variables. They also include techniques for validating form data before the user submits
it to ColdFusion, or on the ColdFusion server.
When you design data validation you consider the following factors:
The validation technique Whether to validate on the clients browser or on the server, and the specific server- or
client-side validation technique, such as whether to validate when a field loses focus or when the user submits the form.
The validation type The specific method that you use to validate the data, including the rules that you apply to test the
Validation techniques
Different validation techniques apply to different ColdFusion tags or coding environments; for example, you can use
masking only in HTML and Flash format cfinput tags. Validation techniques also vary in where and when they
execute; for example, on the client browser when the user submits form data, or on the server when processing data.
The following table describes the ColdFusion validation techniques:
744
Validation technique
Applies to
mask
(mask attribute)
Description
onBlur
(validateat="onBlur" attribute)
cfinput and
cftextarea tags
On the client when the In HTML and XML format, ColdFusion generates
data field loses focus
JavaScript that runs on the browser to check
whether entered data is valid and provide
immediate feedback, if the entry is invalid.
In Flash format, uses Flash built-in validation
routines.
onSubmit
(validateat="onSubmit"
attribute)
cfinput and
cftextarea tags
On the client when the In HTML or XML format, the validation logic is
user clicks Submit
identical to onBlur validation, but the test is not
done until the user submits the form.
In Flash format, this validation type is identical to
onBlur Validation. Flash checks do not
differentiate between the two events for
validation.
onServer
(validateat="onServer"
attribute)
hidden field
cfinput and
cftextarea tags
JavaScript
(onValidate ="function"
attribute)
cfgrid, cfinput,
cfslider,
cftextarea, and
cftree tags in HTML
745
Validation technique
Applies to
Description
IsValid function
ColdFusion variables
cfparam tag
ColdFusion variables
cfargument tag
Note: For more information on ColdFusion error handling, see Handling Errors on page 275.
If you are validating form data, the techniques you use can vary depending on whether you are using HTML, Flash,
or XML forms; for example, different form types have different validation limitations.
Different validation techniques are appropriate for different form controls and data types.
Available techniques vary depending on when and where you want the data validated; on the client or the server,
when the user enters data or submits a form, or when ColdFusion processes a variable or function argument.
Each technique has specific features and considerations, such as the form of user feedback, feature limitations, and
so on.
Security issues or concerns that apply to your environment or application can affect the technique you select.
The table in the preceding section described some of the considerations (see Validation techniques on page 743). The
following table describes additional considerations for selecting a validation technique. For additional considerations
that are specific to form fields, see Validation type considerations on page 749.
746
Validation technique
Features
Considerations
Security issues
mask
Provides immediate
feedback if a user enters
invalid data.
Limited to forms.
JavaScript
Limited to specific
ColdFusion form tags. Calls a
single JavaScript function.
JavaScript levels of support
can vary among browsers,
and users can disable
JavaScript in their browsers.
IsValid function
cfparam tag
cfargument tag
(mask attribute)
onBlur
(validateat="onBlur" attribute)
onSubmit
(validateat="onSubmit" attribute)
onServer
(validateat="onServer" attribute)
(onValidate = "function"
attribute)
None
747
Security considerations
Although form-specific validation techniques provide good methods for preventing users from submitting invalid or
badly formatted data, they cannot prevent users from submitting maliciously formatted data from HTML forms.
Malicious users can circumvent validation techniques that require validation on the browser using JavaScript or
submission of validation rules in hidden fields. If you must use a technique for preventing malicious data submissions,
consider using the following techniques:
The onSubmit or OnBlur validation in Flash forms, which use Flash built-in validation.
The IsValid function and the cfparam, and cfargument tags, which let you test variables and arguments in your
CFML code.
The cfqueryparam tag in cfquery tags, which can help protect databases from malicious query input (see
Enhancing security with cfqueryparam on page 416.
The script protection option, which helps prevent cross-site scripting attacks. You can set this option on the
ColdFusion Administrator Server Settings > Settings page or by using the Application.cfc This.scriptProtect
variable or the cfapplication tag scriptprotect attribute. For more information on cross-site scripting attacks and
this option, see the cfapplication tag page in the CFML Reference.
Description
date
When validating on the server, allows any date/time format that returns true in the IsDate
function, including a time value. When validating on the client, same as USdate.
USdate *
A U.S. date of the format mm/dd/yy, with 1- or 2-digit days and months, and 1-through 4-digit
years. The separators can be slash (/), hyphen (-), or period (.) characters
eurodate *
A date of the format dd/mm/yy, with 1- or 2-digit days and months, and 1- through 4-digit years.
The separators can be slash (/), hyphen (-), or period (.) characters.
time *
When validating on the server, allows any date/time format that returns True in the IsDate
function, including a date value. When validating on the client, allows a time of format hh:mm[:ss]
[A/PM].
float *
A number; allows integers. When validating form fields on the server, integer values are converted
to real numbers.
numeric
A number; allows integers. When validating form fields on the server, integer values are
unchanged.
integer *
An integer.
range *
boolean
A value that can be converted to a Boolean value: Yes, No, True, or False (all case-independent), or
a number.
telephone *
Standard U.S. telephone formats. Allows an initial 1 long-distance designator and up to 5-digit
extensions, optionally starting with x.
zipcode *
U.S. 5- or 9-digit ZIP code format #####-####. The separator can be a hyphen (-) or a space.
748
Type field
Description
creditcard *
Strips blanks and dashes; verifies number using mod10 algorithm. The number must have 1316
digits.
ssn * or social_security_number *
US. Social Security number format, ###-##-####. The separator can be a dash (-) or a space.
email *
A valid e-mail address of the form [email protected]. ColdFusion validates the format only; it
does not check that entry is a valid active e-mail address.
URL *
A valid URL pattern; supports http, https, ftp file, mailto, and news URLs.
guid *
uuid *
A universally unique identifier (UUID) that follows the ColdFusion format, xxxxxxxx-xxxx-xxxxxxxxxxxxxxxxxxxx, where x is a hexadecimal number.
regex * or regular_expression *
Matches the value against a regular expression specified in a pattern attribute. Valid in HTML and
XML format only; ignored in Flash format.
Note: For more details on how ColdFusion handles data when it does onServer and hidden field validation, see
Validating form data using hidden fields on page 755.
The following validation types can only be used in cfinput tags:
Type
Description
maxlength
noblanks
Does not allow fields that consist only of blanks. ColdFusion uses this validation only if the required attribute is
True.
SubmitOnce
Used only with cfformsubmit and image types; prevents the user from submitting the same form multiple
times before until the next page loads, Use this attribute, for example, to prevent a user from submitting an order
form a second time before getting the confirmation for the initial order, and thereby making a duplicate order,
Valid in HTML and XML format only; ignored in Flash format.
You can use the following validation types in cfparam and cfargument tags and the IsValid function only:
Type
Description
any
array
An array of values
binary
A binary value
query
A query object
string
struct
A structure
variableName *
749
The following information describes considerations for validation in cfinput and cftextarea tags, and show a more
complete example.
When you validate form data using onBlur, onSubmit, onServer, or hidden form field validation, you can specify
one or more validation types for each field that you validate. For example, you can specify that a field entry is
required and that it must be numeric. To specify multiple validation types for onSubmit, onBlur, or onServer
validation, specify the type values in a comma-delimited list.
If you use onBlur, onSubmit, or onServer type validation, you can specify only one error message for each field that
you validate. If you use hidden field validation, you can create a custom message for each validation rule (except for
range checking).
In the cfinput tag, most validation type attributes apply only to text or password fields.
Validation algorithm differences: The underlying validation code used when validating form data can differ
depending on the validation technique and the form type. As a result, the algorithms used vary in some instances,
including the following:
The validation algorithms used for date/time values in onSubmit and OnBlur validation are different from those
validation algorithms used for all server-side validation techniques.
The algorithms used for onSubmit and OnBlur validation in Flash can vary from those algorithms used for HTML
or XML format, and generally follow simpler rules.
For detailed information on the validation algorithms used for validation techniques used on the server, see
Validating form data using hidden fields on page 755.
750
<cfif IsDefined("form.fieldnames")>
<cfdump var="#form#"><br>
</cfif>
<cfform name="myform" preservedata="Yes" >
First Name: <cfinput type="text" size="15" name="firstname"
required="yes" message="You must enter a first name."><br>
Last Name: <cfinput type="text" size="25" name="lastname"
required="yes" message="You must enter a last name."><br>
Telephone: <cfinput type="text" size="20" name="telephone"
validate="telephone" message="You must enter your telephone
number, for example 617-555-1212 x1234"><br>
E-mail: <cfinput type="text" size="25" name="email"
validate="email" required="Yes"
message="You must enter a valid e-mail address."><br>
Password:<cfinput type="password" size="12" name="password1"
required="yes" maxlength="12"
message="You must enter a password."><br>
Reenter password:<cfinput type="password" size="12" name="password2"
required="yes" maxlength="12"
message="You must enter your password twice."><br>
We will ask you for the following number, in the range 100-999 if you forget
your password.<br>
Number: <cfinput type="text" size="5" name="chalenge"
validate="range" range="100,999" required="Yes"
message="You must enter a reminder number in the range 100-999."><br>
<cfinput type="submit" name="submitit">
</cfform>
specify a text-only error message to display. Otherwise, ColdFusion uses a default message that includes the name
of the form field that was invalid. (For OnServer validation, you can customize this message, as described in
Handling form field validation errors on page 282.) The following example displays an error message when the
user enters an invalid e-mail address:
E-mail: <cfinput type="text" size="25" name="email"
validate="email" message="You must enter a valid e-mail address.">
2 For hidden form validation, you can specify a text-only error message in the hidden fields value attribute.
Otherwise, ColdFusion uses a default message that includes the name of the form field that was invalid. (You can
customize this message, as described in Handling form field validation errors on page 282.) The following
cfinput tag, for example, uses a hidden field validation to display an error message if the user enters an invalid
address. (It uses onServer validation to display a different error message if the user fails to enter a number.)
Telephone: <cfinput type="text" size="20" name="telephone"
validateat="onServer" required="Yes"
message="You must enter a telephone number">
<cfinput type="hidden" name="telephone_cfformtelephone"
value="The number you entered is not in the correct format.<br>Use a
number such as (617) 555-1212, 617-555-1212, or 617-555-1212 x12345">
751
3 For HTML and XML format forms (using ColdFusion skins), most ColdFusion form tags have an onError
attribute that lets you specify a Javascript function to run if an onSubmit error occurs.
4 For the IsValid function, you write separate code paths to handle valid and invalid data. The following example
shows a simplified case that displays an error message if the user entered an invalid e-mail address, or a different
message if the address is valid:
<cfif IsValid("email", custEmail)>
Thank you for entering a valid address.
<!--- More processing would go here. --->
<cfelse>
You must enter a valid e-mail address.<br>
Click the Back button and try again.
</cfif>
5 For cfparam and cfargument tags, you use standard ColdFusion error-handling techniques. You can include the
tag in a try block and use a catch block to handle the error, or you can use a custom error-handling page. The
following example form action page code uses a custom error page, expresserr.cfm, to handle the error that the
cfparam tag generates if a user submits a form with an invalid e-mail address:
<cferror type="EXCEPTION" exception="expression" template="expresserr.cfm">
<cfif IsDefined("form.fieldnames")>
<cfparam name="form.custEmail" type="email">
<!--- Normal form processing code goes here. --->
</cfif>
In HTML and Flash form format, a mask can control the format of data entered into a text field.
In the cfcalendar tag, and, for Flash format forms, the datefield type cfinput field, a mask can control the
format of the date that ColdFusion uses for the date a user chooses in the displayed calendar.
Note: The standard ColdFusion XML skins do not support masking.
Effect
The following pattern enforces entry of a part number of the format EB-1234-c1-098765, where the user starts the
entry by typing the first numeric character, such as 1. ColdFusion fills in the preceding EB prefix and all hyphen (-)
characters. The user must enter four numbers, followed by two alphanumeric characters, followed by six numbers.
<cfinput type="text" name="newPart" mask="EB-9999-XX-999999" />
752
Note: You cannot force a user to type an A, X, 9, or question mark (?) character. To ensure that a pattern is all-uppercase
or all-lowercase, use the ColdFusion UCase or LCase functions in the action page.
Pattern
DD
MM
MMM
MMMM
YY
YYYY
EEE
EEEE
The following pattern specifies that the Flash form sends the date selected using a datefield input control to
ColdFusion as text in the format 04/29/2004:
<cfinput name="startDate" type="datefield" label="date:" mask="mm/dd/yyyy"/>
753
Special characters
Because special characters are the operators in regular expressions, to represent a special character as an ordinary one,
escape it by preceding it with a backslash. For example, use two backslash characters (\\) to represent a backslash
character.
+ * ? . [ ^ $ ( ) { | \
Any character matches itself if it is not a special character or if a preceding backslash (\) escapes the character.
A backslash (\) followed by any special character matches the literal character itself; that is, the backslash escapes
the special character.
A dash can indicate a range of characters. For example, [a-z] matches any lowercase letter.
If the first character of a set of characters in brackets is the caret (^), the expression matches any character except
those characters in the set. It does not match the empty string. For example: [^akm] matches any character except
a, k, or m. The caret loses its special meaning if it is not the first character of the set.
You can make regular expressions case insensitive by substituting individual characters with character sets; for
example, [Nn][Ii][Cc][Kk] is a case-insensitive pattern for the name Nick (or NICK, or nick, or even nIcK).
You can use the following escape sequences to match specific characters or character classes:
Escape seq
Matches
Escape seq
Meaning
[\b]
Backspace.
\s
\b
\S
\B
A nonword boundary.
\t
Tab.
\cX
\v
Vertical tab.
\d
\w
\D
\W
\f
Form feed.
\n
\n
Line feed.
\ooctal
\r
Carriage return.
\\xhex
754
Parentheses group parts of regular expressions into a subexpression that can be treated as a single unit. For example,
(ha)+ matches one or more instances of ha.
A one-character regular expression or grouped subexpression followed by an asterisk (*) matches zero or more
occurrences of the regular expression. For example, [a-z]* matches zero or more lowercase characters.
A one-character regular expression or grouped subexpression followed by a plus sign (+) matches one or more
occurrences of the regular expression. For example, [a-z]+ matches one or more lowercase characters.
A one-character regular expression or grouped subexpression followed by a question mark (?) matches zero or one
occurrence of the regular expression. For example, xy?z matches either xyz or xz.
The carat (^) at the beginning of a regular expression matches the beginning of the field.
The dollar sign ($) at the end of a regular expression matches the end of the field.
The concatenation of regular expressions creates a regular expression that matches the corresponding
concatenation of strings. For example, [A-Z][a-z]* matches any capitalized word.
The OR character (|) allows a choice between two regular expressions. For example, jell(y|ies) matches either jelly
or jellies.
Curly brackets ({}) indicate a range of occurrences of a regular expression. You use them in the form {m, n} where
m is a positive integer equal to or greater than zero indicating the start of the range and n is equal to or greater than
m, indicating the end of the range. For example, (ba){0,3} matches up to three pairs of the expression ba. The form
{m,} requires at least m occurrences of the preceding regular expression. The form {m} requires exactly m
occurrences of the preceding regular expression. The form {,n} is not allowed.
Backreferences
Backreferencing lets you match text in previously matched sets of parentheses. A slash followed by a digit n (\n) refers
to the nth parenthesized subexpression.
One example of how you can use backreferencing is searching for doubled words; for example, to find instances of the
the or is is in text. The following example shows backreferencing in a regular expression:
(\b[A-Za-z]+)[ ]+\1
This code matches text that contains a word that is repeated twice; that is, it matches a word (specified by the \b word
boundary special character and the [A-Za-z]+) followed by one or more spaces (specified by [ ]+), followed by the
first matched subexpression, the first word, in parentheses. For example, it would match is is, but not This is.
If a caret (^) is at the beginning of a pattern, the field must begin with a string that matches the pattern.
If a dollar sign ($) is at the end of a pattern, the field must end with a string that matches the pattern.
If the expression starts with a caret and ends with a dollar sign, the field must exactly match the pattern.
Expression examples
The following examples show some regular expressions and describe what they match:
755
Expression
Description
[\?&]value=
^[A-Z]:(\\[A-Z0-9_]+)+$
An uppercase Windows directory path that is not the root of a drive and has only letters,
numbers, and underscores in its text.
^(\+|-)?[1-9][0-9]*$
An integer that does not begin with a zero and has an optional sign.
^(\+|-)?[1-9][0-9]*(\.[0-9]*)?$
A real number.
^(\+|-)?[1-9]\.[0-9]*E(\+|-)?[0-9]+$
a{2,4}
A string containing two to four occurrences of a: aa, aaa, aaaa; for example, aardvark, but not
automatic.
(ba){2,}
A string containing least two ba pairs; for example, Ali baba, but not Ali Baba.
Note: An excellent reference on regular expressions is Mastering Regular Expressions by Jeffrey E.F. Friedl, published by
O'Reilly & Associates, Inc.
You can use it with standard HTML tags. For example, you can validate data in an HTML input tag. This feature
was useful in releases previous to ColdFusion MX 7, because the cfinput tag did not support all HTML type
attributes.
It is backward-compatible with validation previous to ColdFusion MX 7, when hidden field validation was the only
way to do validation on the server.
Because you use a separate tag for each validation type, if you specify multiple validation rules for a field, you can
specify a different error message for each rule.
You can use hidden field validation with any form field type that submits a data value, not input, cfinput,
textarea, or cftextarea.
Create one HTML input element or CFML cfinput tag of type="hidden" for each validation rule.
Specify the name of the field to validate as the first part of the hidden field name.
Specify the type of validation, starting with an underscore character (_), as the second part of the hidden field name.
You can specify multiple rules for each form data field. For example, to specify range and required validation for a
field named myValue, create hidden myValue_cfformrange and myValue_cfformrequired fields.
For most types of validation, specify the error message as the field value attribute.
For range, maximum length, or regular expression validation, specify the rule, such as the maximum length, in the
value attribute. For these validation types, you cannot specify a custom error message.
The following example uses hidden fields to require data in a date field and ensure that the field contains a date. It
consists only of HTML tags.
756
Use the following suffixes at the end of hidden form field names to specify the validation type. The type identifier
always starts with an underscore. Several validation rules have two names you can use. The names that do not start
with _cf were used in earlier releases and are retained for backward compatibility. For consistency and clarity, Adobe
recommends using the names that start with _cf in new forms.
Field name suffix
Verifies
_integer, _cfforminteger
_cfformnumeric
Any numeric value. Treats the initial characters $ +as valid input, but does NOT remove them
from the number.
_float, _cfformfloat
Any value (including an integer) that can be represented as a floating point number with up to 12
significant digits. Treats the initial characters $ + as valid input, but removes them from the
number.
Converts input data to a real number; for example a dump of an integer value on the action page
includes a decimal point followed by a 0.
_range, _cfformrange
A numeric value within boundaries specified by the value attribute. Specify the range in the value
attribute using the format min=minvalue max=maxvalue. You cannot specify a custom error
message for this validation.
_date, _cfformdate
A date in any format that ColdFusion can understand; converts the input to ODBC date format.
Allows entry of a time part, but removes it from the ODBC value.
_cfformusdate
A date in the form m/d/y, m-d-y , or m.d.y, The m and d format can be 1 or 2 digits; y can be 2 or 4
digits. Does not convert the string to an ODBC value and does not allow a time part.
_eurodate, _cfformeurodate
A date in the form d/m/y, d-m-y, or d.m.y. The m and d format can be 1 or 2 digits; y can be 2 or 4
digits. Converts the input to ODBC date format. Allows entry of a time part, but removes it from the
ODBC value.
_time, _cfformtime
A time. Can be in 12-hour or 24-hour clock format, and can include seconds in the form hh:mm:ss
or a case-independent am or pm indicator.
Converts the input to ODBC time format. Allows entry of a date part, but removes it from the ODBC
value.
_cfformcreditcard
After stripping blanks and dashes, a number that conforms to the mod10 algorithm. Number must
have 13-16 digits.
_cfformSSN,
_cfformsocial_security_number
A nine-digit Social Security number. Can be of the form xxx-xx-xxxx or xxx xx xxxx.
_cfformtelephone
Standard U.S. telephone formats. Does not support international telephone numbers.
Allows area codes with or without parentheses, and hyphens (-), spaces, periods, or no separators
between standard number groups. Can be preceded by a 1 long-distance designator, and can end
with an up-to-5 digit extension, optionally starting with x. The area code and exchange must begin
with a digit in the range 1 - 9.
_cfformzipcode
A 5-digit or 9-digit U.S. ZIP code. In 9-digit codes, precede the final four digits by a hyphen (-) or
space.
_cfformemail
A valid e-mail address. Valid address characters are a-zA-Z0-9_- and the period and separator.
There must be a single at sign (@) and the text after the @ character must include a period, as in
[email protected] or [email protected].
757
Verifies
_cfformURL
A valid URL. Must start with http:\\, https:\, ftp:\, file:\, mailto:, or news:. Can include, as appropriate,
user name and password designators and query strings. The main part of the address can only have
the characters A-Za-z0-9 and -.
_cfformboolean
_cfformUUID
A universally unique identifier (UUID) that follows the ColdFusion format, xxxxxxxx-xxxx-xxxxxxxxxxxxxxxxxxxx, where x is a hexadecimal number.
_cfformGUID
_cfformnoblanks
The field must not include blanks. ColdFusion uses this validation only if you also specify a
_required hidden field.
_cfformmaxlength
The number of characters must not exceed the number specified by the tag value attribute.
_cfformregex,
_cfformregular_expression
The data must match a JavaScript regular expression specified by the tag value attribute.
_required, _cfformrequired
Use hidden field validation if you want to validate data from standard HTML input tags. The cfinput and
cftextarea tags include a validateAt attribute that provides a simpler method for specifying server-side
validation.
Consider using hidden field validation with the cfinput and cftextarea tags if you specify multiple validation
rules for a single field and want to provide a separate error message for each validation.
758
<html>
<head>
<title>Simple Data Form</title>
</head>
<body>
<h2>Simple Data Form</h2>
<!--- Form part. --->
<form action="datatest.cfm" method="Post">
<input type="hidden"
name="StartDate_cfformrequired"
value="You must enter a start date.">
<input type="hidden"
name="StartDate_cfformdate"
value="Enter a valid date as the start date.">
<input type="hidden"
name="Salary_cfformrequired"
value="You must enter a salary.">
<input type="hidden"
name="Salary_cfformfloat"
value="The salary must be a number.">
Start Date:
<input type="text"
name="StartDate" size="16"
maxlength="16"><br>
Salary:
<input type="text"
name="Salary"
size="10"
maxlength="10"><br>
<input type="reset"
name="ResetForm"
value="Clear Form">
<input type="submit"
name="SubmitForm"
value="Insert Data">
</form>
<br>
<!--- Action part. --->
<cfif isdefined("Form.StartDate")>
<cfoutput>
Start Date is: #DateFormat(Form.StartDate)#<br>
Salary is: #DollarFormat(Form.Salary)#
</cfoutput>
</cfif>
</html>
When the user submits this form, ColdFusion scans the form fields to find any validation rules. It then uses the rules
to analyze the users input. If any of the input rules are violated, ColdFusion displays an error page with the error
message that you specified in the hidden fields value attribute. The user must go back to the form, correct the
problem, and resubmit the form. ColdFusion does not accept form submission until the user enters the entire form
correctly.
759
Because numeric values often contain commas and currency symbols, ColdFusion automatically deletes these
characters from fields with _cfforminteger and _cfformfloat rules before it validates the form field and passes the data
to the form's action page. ColdFusion does not delete these characters from fields with _cfformnumeric rules.
Reviewing the code
The following table describes the code and its function:
Code
Description
<form action="datatest.cfm" method="Post"> Gathers the information from this form sends it to the dataform.cfm page (this
Requires input into the StartDate input field. If there is no input, displays the error
information You must enter a start date. Requires the input to be in a valid date
format. If the input is not valid, displays the error information Enter a valid date as
the start date.
<input type="hidden"
name="Salary_cfformrequired" value="You
must enter a salary.">
<input type="hidden"
name="Salary_cfformfloat" value="The
salary must be a number.">
Requires input into the Salary input field. If there is no input, displays the error
information You must enter a salary. Requires the input to be in a valid number.
If it is not valid, displays the error information The salary must be a number.
Start Date:
<input type="text" name="StartDate"
size="16" maxlength="16"><br>
Creates a text box called StartDate in which users can enter their starting date.
Makes it 16-characters wide.
Salary:
<input type="text" name="Salary" size="10"
maxlength="10"><br>
Creates a text box called Salary in which users can enter their salary. Makes it tencharacters wide.
<cfif isdefined("Form.StartDate")>
<cfoutput>
Start Date is:
#DateFormat(Form.StartDate)#<br>
Salary is: #DollarFormat(Form.Salary)#
</cfoutput>
</cfif>
Displays the values of the StartDate and Salary form fields only if they are defined.
They are not defined until you submit the form, so they do not appear on the initial
form. Uses the DateFormat function to display the start date in the default date
format. Uses the DollarFormat function to display the salary with a dollar sign and
commas.
cfgrid
cfinput
cfslider
cftextarea
cftree
ColdFusion passes the following arguments to the JavaScript function that you specify in the onValidate attribute:
760
761
}
//-->
</script>
</head>
<body>
<h2>JavaScript validation test</h2>
<!--- Form is submitted only if the password is valid. --->
<cfif IsDefined("Form.passwd1")>
<p>Your Password if valid.</p>
</cfif>
<p>Please enter your new password:</p>
<cfform name="UpdateForm" preservedata="Yes" >
<!--- The onValidate attribute specifies the JavaScript validation
function. The message attribute is the message that appears
if the validation function returns False. --->
<cfinput type="password" name="passwd1" required="YES"
onValidate="testpasswd"
message="Your password must have 8-12 characters and include uppercase
and lowercase letters and at least one number."
size="13" maxlength="12">
<input type="Submit" value=" Update... ">
</cfform>
</body>
</html>
cfgrid
cfinput
cfselect
cfslider
cftextinput
cftree
ColdFusion passes the following JavaScript objects to the function in the onerror attribute:
762
The error message text specified by the CFML tags message attribute
The following example shows a form that uses an onError attribute to tell ColdFusion to call a showErrorMessage
JavaScript function that uses the alert method to display an error message. The function assembles the message from
the invalid value and the contents of the cfinput tags message attribute.
<!--- The JavaScript function to handle errors.
Puts a message, including the field name and value, in an alert box. --->
<script>
<!-function showErrorMessage(form, ctrl, value, message) {
alert("The value " + value +" of the " + ctrl + " field " + message);
}
//-->
</script>
<!--- The form.
The cfinput tags use the onError attribute to override the ColdFusion
default error message mechanism. --->
<cfform>
<!--- A minimum quantity is required and must be a number. --->
Minimum Quantity: <cfinput type="Text" name="MinQuantity"
onError="showErrorMessage" validate="numeric" required="Yes"
message="is not a number." ><br>
<!--- A maximum quantity is optional, but must be a number if supplied. --->
Maximum Quantity: <cfinput type="Text" name="MaxQuantity"
onError="showErrorMessage" validate="numeric"
message="is not a number." ><br>
<cfinput type="submit" name="submitit">
</cfform>
Validating data with the IsValid function and the cfparam tag
The IsValid function and cfparam tag validate any ColdFusion variable value, not just forms variables. Because they
reside entirely on the ColdFusion server, they can provide a secure mechanism for ensuring that the required
validation steps get performed. Users cannot evade any of the checks by modifying the form data that gets submitted.
These techniques also provide greater flexibility in how you respond to user errors, because you can use full CFML
syntax in your error-handling code.
These two validation techniques operate as follows:
The IsValid function tests the value of a ColdFusion variable. If the value is valid, it returns True; if the value is
invalid, it returns False.
The cfparam tag with a type attribute tests the value of a ColdFusion value for validity. If the value is valid, it does
nothing; if the value is invalid, it throws a ColdFusion expression exception.
You can use either technique interchangeably. The technique you choose should depend on your coding style and
programming practices. It can also depend on the specific information that you want to display if an error occurs.
763
<!--- Action code. First make sure the form was submitted. --->
<cfif isDefined("form.saveSubmit")>
<cfif isValid("integer", form.UserID) and isValid("email", form.emailAddr)
and isValid("telephone", form.phoneNo)>
<cfoutput>
<!--- Application code to update the database goes here --->
<h3>The e-mail address and phone number for user #Form.UserID#
have been added</h3>
</cfoutput>
<cfelse>
<H3>Please enter a valid user ID, phone number, and e-mail address.</H2>
</cfif>
<cfelse>
</cfif>
<!--- The form. --->
<cfform action="#CGI.SCRIPT_NAME#">
User ID:<cfinput type="Text" name="UserID"><br>
Phone: <cfinput type="Text" name="phoneNo"><br>
E-mail: <cfinput type="Text" name="emailAddr"><br>
<cfinput type="submit" name="saveSubmit" value="Save Data"><br>
</cfform>
764
765
<cfcatch type="expression">
<cfset goodData="No">
<cfoutput>
Invalid e-mail address.<br>
#cfcatch.detail#<br><br>
</cfoutput>
</cfcatch>
</cftry>
<!--- The cftry block for testing the telephone number value. --->
<cftry>
<cfparam name="form.phoneNo" type="telephone">
<cfcatch type="expression">
<cfset goodData="No">
<cfoutput>
Invalid telephone number.<br>
#cfcatch.detail#<br><br>
</cfoutput>
</cfcatch>
</cftry>
<!--- Do this only if the validity indicator was not set to False in a
validation catch block. --->
<cfif goodData>
<!--- Application code to update the database goes here. --->
<cfoutput>
<h3>The e-mail address and phone number for user #Form.UserID#
have been added</h3>
</cfoutput>
</cfif> <!--- goodData is True--->
</cfif> <!--- Form was submitted. --->
<cfform action="#CGI.SCRIPT_NAME#" preservedata="Yes">
User ID:<cfinput type="Text" name="UserID"><br>
Phone: <cfinput type="Text" name="phoneNo"><br>
E-mail: <cfinput type="Text" name="emailAddr"><br>
<cfinput type="submit" name="saveSubmit" value="Save Data"><br>
</cfform>
They are browser-independent. Flash Player works in all commonly used browsers on Windows and Macintosh
systems, and in Netscape and Mozilla on Linux.
By default, they present a modern, visually pleasing appearance, and you can apply predefined color skins or
customize the appearance with specifications like those specifications in a Cascading Style Sheet (CSS).
766
They let you develop complex, multipart forms that do not require multiple pages, by using tabbed or accordionstyle dialog boxes.
Each tab contains a different section of the overall form, and users can enter data on both tabs before submitting
the form. This technique can eliminate the need for multiple forms on multiple HTML pages.
The first and last names are required fields, indicated by the red asterisks.
The Flash form automatically fills the e-mail field with data from the name fields, but the user can override this
information.
When the user selects the date field, a calendar automatically opens for picking the date.
Plain text and HTML tags in the body of a Flash Form have no effect.
Specify all form content inside CFML tags that support Flash forms.
767
ColdFusion provides two tags that let you take advantage of Flash features and perform tasks that you would
otherwise do in HTML: use the cfformitem tag to add text blocks and horizontal and vertical rules to your form,
and you use the cfformgroup tag to structure your form.
Standard ColdFusion forms tags, such as cfinput and cftree, include attributes that work only with Flash forms,
and attribute values that let you specify form style and behavior. These tags include the skin attribute with many
Flash-specific style attribute values for appearance, and the bind attribute for filling a field value with data from
other fields.
The reference pages for the individual tags in the CFML Reference describe the form tags and their features,
indicating which attributes and values work with Flash forms.
The cfcalendar, cfgrid, cfinput, cfselect, cftextarea, and cftree tags create controls for data display and
user input.
The cfformitem tag lets you add formatted or unformatted text, spacers, and horizontal and vertical rules without
using HTML.
The cfformgroup tag creates containers, such as horizontally aligned boxes or tabbed navigators, that let you
group, organize, and structure the form contents.
Flash forms follow a hierarchical structure of containers and children.
1 The cfform tag is the master container, and its contents are child containers and controls.
2 The cfformgroup tag defines a container that organizes its child elements.
3 All other tags create individual controls, including display elements such as rules.
For example, the image in the About Flash forms section has the following hierarchical structure of containers and
children. (This outline only shows the structure of the page that is visible in the image. It omits the structure of the
Preferences tab.)
1
2
3
4
5
5
5
4
4
4
4
4
4
4
3
2
3
3
cfform
cfformgroup type="tabnavigator" -- Tab navigator container
cfformgroup type="page" -- Tabbed page container, child of tabnavigator
cfformgroup type="horizontal" -- Aligns its two children horizontally
cfinput type="text" -- First name input control
cfinput type="spacer" -- Space between the name input controls
cfinput type="text" -- Last name input control
cfformitem type="hrule" -- Displays a rule
cfformitem type="html" -- Displays formatted text
cffinput type="text" -- E-mail input control
cfformitem type="hrule" -- Displays a rule
cfinput type="text" -- Phone number input control
cfinput type="spacer" -- Space between the phone and date controls
cfinput type="datefield" -- Date input control
cfinput type="page" -- Second tabbed page container for preferences
.
.
cfformgroup type="horizontal" -- Follows the tabnavigator in the form
cfinput type="submit" -- Submit button control
cfinput type="reset" -- Reset button control
768
Adding text, images, rules, and space with the cfformitem tag
Because Flash forms do not support inline HTML, you use the cfformitem tag to add text blocks and horizontal and
vertical rules to your form. (Flash form controls, such as cfinput, use the label or value attribute to specify text
labels.) You can also use the cfformitem tag to add spacers between visual form elements.
The cfformitem type="hrule" and cfformitem type="vrule" tags put horizontal and vertical rules in the form.
You can specify the rule thickness, color, and shadow characteristics by using style specifications. For more
information on specifying rule styles, see Styles for cfformitem with hrule or vrule type attributes in ColdFusion Flash
Form Style Reference in the CFML Reference.
The cfformitem type="spacer" tag puts a blank space of the specified height and width on the form. This tag type
does not use styles; it can be useful in improving the form appearance by helping you control the form layout.
The cfformitem type="text" tag lets you insert plain text in the form You can use the style attribute to apply a
consistent format to the text.
The cfformitem type="html" tag lets you insert formatted text and images in the form. You can include basic
HTML-style formatting tags in the body of this tag to add images and to format and style the text.
You can use the following formatting tags and attributes in the body of a cfformitem type="html" tag:
Tag
Valid attributes
href
target
None.
br
None.
font
color
Must be in hexadecimal format, such as #FF00AA. Use a single number sign (#) character.
faceC
an be a comma-delimited list of font face names; Flash uses the first font that is available on the client
system.
size
None.
img
li
None.
textformat
None.
Description
src
(Required) URL or path to a JPEG or SWF file. Images are not displayed until they have downloaded completely.
Flash Player does not support progressive JPEG files.
width
height
769
Attribute
Description
align
Horizontal alignment of the embedded image within the text field. Valid values are left and right. The default
value is left.
hspace
Number of pixels of horizontal space that surround the image where no text appears. The default value is 8.
vspace
Number of pixels of vertical space that surround the image where no text appears. The default value is 8.
Note: Because of the Flash dynamic sizing rules, to ensure that the image displays properly, you sometimes have to specify
the formitem tag height attribute and the width and height attributes for the form or the containing cfformgroup
tag. Also, the image always displays on a new line, not inline with text, and text that follows the image in your code
occupies any available space to the right of the image.
The textformat tag is specific to Flash, and has the following attributes:
Attribute
Description
blockindent
indent
Indentation from the left margin to the first character in the paragraph.
leading
leftmargin
rightmargin
tabstops
Custom tab stops as an array of nonnegative integers. To specify tabs in text, use the \t escape character.
770
Description
horizontal
Arranges individual controls horizontally, and optionally applies a label to the left of the controls. Use only for
arranging ColdFusion form controls, including cfformitem controls. As a general rule, do not use to organize
cfformgroup containers; use the hbox attribute instead.
If you put other cfformgroup tags inside a horizontal form group, the controls inside the included
cfformgroup tag do not align with other controls in the horizontal group.
vertical
Arranges individual controls vertically, and optionally applies a label to the left (not top) of the controls. Use only
for groups of ColdFusion form controls, including cfformitem controls. As a general rule, do not use to organize
cfformgroup containers; use the vbox attribute instead.
If you put other cfformgroup tags inside a vertical form group, the controls inside the included
cfformgroup tag do not align with other controls in the vertical group.
hbox
Arranges groups of controls horizontally. Does not apply a label. Use this attribute value to arrange other
cfformgroup containers. This tag does not enforce alignment of child controls that have labels, so you should
not use it to align individual controls.
vbox
Arranges groups of controls vertically. Does not apply a label. Use this attribute value to arrange other
cfformgroup containers. This tag does not enforce alignment of child controls that have labels, so do not use it
to align individual controls.
hdividedbox
Arranges two or more children horizontally, and places divider handles between the children that users can drag
to change the relative sizes of the children. Does not apply a label. The direct children of an hdividedbox
container must be cfformgroup tags with type attributes other than horizontal or vertical.
vdividedbox
Arranges two or more children vertically, and places divider handles between the children that users can drag to
change the relative sizes of the children. Does not apply a label. The direct children of a vdividedbox container
must be cfformgroup tags with type attributes other than horizontal or vertical.
tile
Arranges its children in a rectangular grid in row-first order. Does not apply a label.
panel
Consists of a title bar containing the label attribute text, a border, and a content area with vertically arranged
children.
accordion
Places each of its child pages in an accordion pleat with a label bar. Displays the contents of one pleat at a time.
Users click the labels to expand or contract the pleat pages. Does not apply a label.
tabnavigator
Places each of its children on a tabbed page. Users click the tabs to display a selected page. Does not apply a label.
page
The immediate child of an accordion or tab navigator container. Specifies the label on the pleat bar or tab, and
arranges its child containers and controls vertically.
For more information on using the accordion, tabnavigator, and pagecfformgroup types, see Creating complex
forms with accordion and tab navigator containers on page 773.
Example: structuring with the cfformgroup tag
The following example shows a form with an hdividedbox container with two vbox containers. The left box uses a
horizontal container to arrange two radio buttons. The right box uses a tile container to lay out its check boxes.
You can drag the divider handle to resize the two boxes. When you submit the form, the ColdFusion page dumps the
Form scope to show the submitted data.
771
<cfif Isdefined("Form.fieldnames")>
<cfdump var="#form#" label="form scope">
<br><br>
</cfif>
<cfform name="myform" height="200" width="460" format="Flash" skin="HaloBlue">
<cfformitem type="html" height="20">
<b>Tell us your preferences</b>
</cfformitem>
<!--- Put the pet selectors to the left of the fruit selectors. --->
<cfformgroup type="hdividedbox" >
<!--- Group the pet selector box contents, aligned vertically. --->
<cfformgroup type="VBox"height="130">
<cfformitem type="text" height="20">
Pets:
</cfformitem>
<cfformgroup type="vertical" height="80">
<cfinput type="Radio" name="pets" label="Dogs" value="Dogs"
checked>
<cfinput type="Radio" name="pets" label="Cats" value="Cats">
</cfformgroup>
</cfformgroup>
<!--- Group the fruit selector box contents, aligned vertically. --->
<cfformgroup type="VBox" height="130">
<cfformitem type="text" height="20">
Fruits:
</cfformitem>
<cfformgroup type="tile" height="80" width="190" label="Tile box">
<--- Flash requires unique names for all controls --->
<cfinput type = "Checkbox" name="chk1" Label="Apples"
value="Apples">
<cfinput type="Checkbox" name="chk2" Label="Bananas"
value="Bananas">
<cfinput type="Checkbox" name="chk3" Label="Pears"
value="Pears">
<cfinput type="Checkbox" name="chk4" Label="Oranges"
value="Oranges">
<cfinput type="Checkbox" name="chk5" Label="Grapes"
value="Grapes">
<cfinput type="Checkbox" name="chk6" Label="Cumquats"
value="Cumquats">
</cfformgroup>
</cfformgroup>
</cfformgroup>
<cfformgroup type="horizontal">
<cfinput type="submit" name="submit" width="100" value="Show Results">
<cfinput type="reset" name="reset" width="100" value="Reset Fields">
</cfformgroup>
</cfform>
772
If you do not specify the height and width attributes in the cfform tag, Flash reserves the full dimensions of the
visible browser window, if the form is not in a table, or the table cell, if the form is in a table, even if they are not
required for the form contents. Any HTML output that precedes or follows the form causes the output page to
exceed the size of the browser window.
If you do not specify the height or width of a control, including a form group, Flash adjusts the dimensions, trying
to fit the controls in the available space. For example, Flash often extends input boxes to the width of the containing
control, if not otherwise specified.
In general, it is best to use the following process when you design your Flash form.
Determine the sizes of a Flash form and its controls
1 When you first create the form, dont specify any height and width attributes on the form or its child tags. Run
the form and examine the results to determine height and width values to use.
2 Specify height and width attributes in the cfform tag for the desired dimensions of the form. You can specify
absolute pixel values, or percentage values relative to the size of the containing window.
3 Specify any height or width attributes on individual tags. These values must be in pixels.
4 Repeat step 3 for various tags, and possibly step 2, until your form has a pleasing appearance.
One example that can use a repeater is a form that lets a teacher select a specific class and update the student grades.
Each class can have a different number of students, so the form must have a varying number of input lines. Another
example is a shopping cart application that displays the product name and quantity ordered and lets users change the
quantity.
The following example uses the cfformgroup tag with a repeatertype attribute value to populate a form. It creates
a query, and uses the repeater to iterate over a query and create a firstname and lastname input box for each row in the
query.
773
<cfif IsDefined("Form.fieldnames")>
<cfdump var="#form#" label="form scope">
<br><br>
</cfif>
<cfscript>
q1 = queryNew("id,firstname,lastname");
queryAddRow(q1);
querySetCell(q1, "id", "1");
querySetCell(q1, "firstname", "Rob");
querySetCell(q1, "lastname", "Smith");
queryAddRow(q1);
querySetCell(q1, "id", "2");
querySetCell(q1, "firstname", "John");
querySetCell(q1, "lastname", "Doe");
queryAddRow(q1);
querySetCell(q1, "id", "3");
querySetCell(q1, "firstname", "Jane");
querySetCell(q1, "lastname", "Doe");
queryAddRow(q1);
querySetCell(q1, "id", "4");
querySetCell(q1, "firstname", "Erik");
querySetCell(q1, "lastname", "Pramenter");
</cfscript>
<cfform name="form1" format="flash" height="220" width="450">
<cfselect label="select a teacher" name="sel1" query="q1" value="id"
display="firstname" width="100" />
<cfformgroup type="repeater" query="q1">
<cfformgroup type="horizontal" label="name">
<cfinput type="Text" name="fname"bind="{q1.currentItem.firstname}">
<cfinput type="Text" name="lname" bind="{q1.currentItem.lastname}">
</cfformgroup>
</cfformgroup>
<cfinput type="submit" name="submitBtn" value="Send Data" width="100">
</cfform>
774
An accordion container places each logical form page on an accordion pleat. Each pleat has a label bar; when the user
clicks a bar, the current page collapses and the selected page expands to fill the available form space. The following
image shows a three-pleat accordion, open to the middle pleat, Preferences:
A tab navigator container places each logical form page on a tabbed frame. When the user clicks a tab, the selected page
replaces the previous page. The image in About Flash forms shows a tab navigator container.
The following example generates a two-tab navigator container that gets contact information and preferences. You can
change it to an accordion container by changing the type attribute of the first cfformgroup tag from tabnavigator
to accordion. To prevent the accordion from having scroll bars, increase the cfform tag height attribute to 310 and
the tabnavigator tag height attribute to 260.
<cfif IsDefined("Form.fieldnames")>
<cfdump var="#form#" label="form scope">
<br><br>
</cfif>
<br>
<cfform name="myform" height="285" width="480" format="Flash" skin="HaloBlue">
<cfformgroup type="tabnavigator" height="240" style="marginTop: 0">
<cfformgroup type="page" label="Contact Information">
<!--- Align the first and last name fields horizontally. --->
<cfformgroup type="horizontal" label="Your Name">
<cfinput type="text" required="Yes" name="firstName" label="First"
value="" width="100"/>
<cfinput type="text" required="Yes" name="lastName" label="Last"
value="" width="100"/>
</cfformgroup>
<cfformitem type="hrule" />
<cfformitem type="HTML"><textformat indent="95"><font size="-2">
Flash fills this field in automatically.
You can replace the text.
</font></textformat>
</cfformitem>
<!--- The bind attribute gets the field contents from the firstName
and lastName fields as they get filled in. --->
<cfinput type="text" name="email" label="email"
bind="{firstName.text}.{lastName.text}@mm.com">
<cfformitem type="spacer" height="3" />
<cfformitem type="hrule" />
<cfformitem type="spacer" height="3" />
<cfinput type="text" name="phone" validate="telephone" required="no"
775
label="Phone Number">
<cfinput type="datefield" name="mydate1" label="Requested date">
</cfformgroup>
<cfformgroup type="page" label="Preferences" style="marginTop: 0">
<cfformitem type="html" height="20">
<b>Tell us your preferences</b>
</cfformitem>
<!--- Put the pet selectors to the left of the fruit selectors. --->
<cfformgroup type="hdividedbox" >
<!--- Group the pet selector box contents, aligned vertically. --->
<cfformgroup type="VBox"height="130">
<cfformitem type="text" height="20">
Pets:
</cfformitem>
<cfformgroup type="vertical" height="80">
<cfinput type="Radio" name="pets" label="Dogs" value="Dogs"
checked>
<cfinput type="Radio" name="pets" label="Cats" value="Cats">
</cfformgroup>
</cfformgroup>
<!--- Group the fruit selector box contents, aligned vertically. --->
<cfformgroup type="VBox" height="130">
<cfformitem type="text" height="20">
Fruits:
</cfformitem>
<cfformgroup type="tile" height="80" width="190" label="Tile box">
<--- Flash requires unique names for all controls. --->
<cfinput type = "Checkbox" name="chk1" Label="Apples"
value="Apples">
<cfinput type="Checkbox" name="chk2" Label="Bananas"
value="Bananas">
<cfinput type="Checkbox" name="chk3" Label="Pears"
value="Pears">
<cfinput type="Checkbox" name="chk4" Label="Oranges"
value="Oranges">
<cfinput type="Checkbox" name="chk5" Label="Grapes"
value="Grapes">
<cfinput type="Checkbox" name="chk6" Label="Kumquats"
value="Cumquats">
</cfformgroup>
</cfformgroup>
</cfformgroup>
</cfformgroup>
</cfformgroup>
<cfformgroup type="horizontal">
<cfinput type = "submit" name="submit" width="100" value = "Show Results">
<cfinput type = "reset" name="reset" width="100" value = "Reset Fields">
</cfformgroup>
</cfform>
776
cfinputtype="text" or
cftextarea text
bind="{sourceName.text}"
bind="{sourceName.selectedData}"
bind="{sourceName.selectedNode.getProperty('data').value}
bind="{sourceName.selectedItem.COLUMNAME}"
bind="{sourceName.selectedItem.data}"
Note: If you use the bind attribute, you cannot use the value attribute.
The following rules and techniques apply to the binding formats:
The sourceName value in these formats is the name attribute of the tag that contains the element that you are
binding to.
You can bind to additional information about a selected item in a tree. Replace value with display to get the
displayed value, or with path to get the path to the node in the tree.
You can bind to the displayed value of a cfselect item by replacing data with label.
If the user selects multiple items in a cfselect control, the selectedItem object contains the most recent selection,
and a selectedItems array contains all selected items. You can access the individual values in the array, as in
myTree.selectedItems[1].data. The selectedItems array exists only if the user selects multiple items; otherwise, it is
undefined.
form.
Styles provide a finer-grained level of control than skins. Each style specifies a particular characteristic for a single
777
You can use both techniques in combination: you can specify a skin for your form and use styles to specify the
appearance (such as input text font) of individual controls.
For detailed information on the style names and values that you can use, see ColdFusion Flash Form Style Reference
in the CFML Reference.
haloBlue
haloGreen (the default)
haloOrange
haloSilver
cfform
cfformgroup
cfcalendar
cfgrid
cfinput
cfselect
cftextarea
cftree
The attributes for the cfform and cfformgroup generally apply to all the form or form groups children.
Flash supports many, but not all, standard CSS styles. ColdFusion Flash forms only support applying specific CSS
style specifications to individual CFML tags and their corresponding Flash controls and groups. You cannot use an
external style sheet or define a document-level style sheet, as you can for HTML forms.
For example, the following code specifies three style values for a text input control:
<cfinput type="text" name="text2" label="Last"
style="borderSyle:inset; fontSize:12; backgroundColor:##FFEEFF">
778
Length format
You specify styles that take length or dimension values, including font sizes, in pixels.
The fontSize style property lets you use a set of keywords in addition to numbered units. You can use the following
keywords when you set the fontSize style property. The exact sizes are defined by the client browser.
xx-small
x-small
small
medium
large
x-large
xx-large
The following cfinput tag uses the style attribute with a fontSize keyword to specify the size of the text in the
input box:
<cfinput type="text" name="text1" style="fontSize:X-large" label="Name">
Time format
You specify styles that take time values, such as the openDuration style that specifies how fast an accordion pleat
opens, in milliseconds. The following example shows an accordion tag that takes one-half second to change between
accordion pleats:
<cfformgroup type="accordion" height="260" style="openDuration: 500">
Color format
You define color values, such as those for the backgroundColor style, in the following formats:
Format
Description
hexadecimal
Hexadecimal colors are represented by a six-digit code preceded by two number sign characters (##). Two # characters
are required to prevent ColdFusion from interpreting the character. The range of possible values is ##000000 to
##FFFFFF.
VGA color names are a set of 16 basic colors supported by all browsers that support CSS. The available color names are
Aqua, Black, Blue, Fuchsia, Gray, Green, Lime, Maroon, Navy, Olive, Purple, Red, Silver, Teal, White, and
Yellow. Some browsers support a larger list of color names. VGA color names are not case-sensitive.
779
Styles can be inheritable or noninheritable. If a style is noninheritable, it only affects the tag, and does not affect any of
its children. For example, to maintain a consistent background color in an hbox form group and its children tags,
specify the color in all tags. If a style is inheritable, it applies to the tag and its children.
780
Form and control events, such as the onSubmit attribute of the cfform tag, or the onChange and onClick
attributes of the cfinput tag. The attribute description on the tag reference pages in the CFML Reference list the
event attributes.
Bind expressions, which you can use to set field values. For more information on binding data, see Binding data
in Flash forms on page 776.
Your ActionScript code can be inline in the form attribute specification, you can make a call to a custom function
that you define, or you can use the ActionScript include command in the attribute specification to get the
ActionScript from a .as file.
The following example shows a simple Fahrenheit to Celsius converter that does the conversion directly on the
client, without requiring the user to submit a form to the ColdFusion server.
<cfform format="flash" width="200" height="150">
<cfinput type="text" name="fahrenheit" label="Fahrenheit" width="100"
value="68">
<cfinput type="text" name="celsius" label="Celsius" width="100">
<cfinput type="button" name="convert" value="Convert" width="100"
onClick="celsius.text = Math.round((farenheit.text-32)/1.8*10)/10">
</cfform>
781
Note: You do not use the text property (for example, fieldname.text) to access hidden fields. To access a hidden field,
use the format formname.fieldname = 'value'.
resetForm()
submitForm()
You can use the following custom functions in cfgrid tags only to insert and delete rows in the grid:
GridData.insertRow(gridName)
GridData.deleteRow(gridName)
The following example shows how you can use the two GridData functions to add custom buttons that add and delete
rows from a Flash form. These buttons are equivalent to the buttons that ColdFusion creates if you specify
insert="yes" and delete="yes" in the cfgrid tag, but they allow you to specify you own button text and
placement. This example puts the buttons on the side of the grid, instead of below it and uses longer than standard
button labels.
<cfform format="flash" height="265" width="400">
<cfformitem type="html">
You can edit this grid as follows:
<ul>
<li>To change an item, click the field and type.</li>
<li>To add a row, click the Insert Row button and type in the fields
in the highlighted row.</li>
<li>To delete a row, click anywhere in the row and click the
Delete Row button</li>
</ul>
<p><b>When you are done, click the submit button.</b></p>
</cfformitem>
<!--- The hbox aligns the grid and the button vbox horizontally --->
<cfformgroup type="hbox" style="verticalAlign:bottom;
horizontalAlign:center">
<!--- To make all elements align properly, all of the hbox children must
be containers, so we must put the cfgrid tag in a vbox tag. --->
<cfformgroup type="vbox">
<!-- An editable grid with hard coded data (for simplicity).
By default, this grid does not have insert or delete buttons. --->
<cfgrid name="mygrid" height="120" width="250" selectmode="edit">
<cfgridcolumn name="city">
<cfgridcolumn name="state">
<cfgridrow data="Rockville,MD">
<cfgridrow data="Washington,DC">
<cfgridrow data="Arlington,VA">
</cfgrid>
</cfformgroup>
<!--- Group the Insert and Delete buttons vertically;
use a vbox to ensure correct alignment. --->
782
Only data must be dynamic. Whenever a variable name changes, or a form characteristic, such as an element width
or a label changes, the Flash output must be recompiled. If a data value changes, the output does not need to be
recompiled.
Use cfformgroup
type="repeater" if you must loop no more than ten times over no more than ten elements.
This tag does not require recompiling when the number of elements changes. It does have a processing overhead
that increases with the number of loops and elements, however, so for large data sets or many elements, it is often
more efficient not to use the repeater.
If the timeout value is 0, or the time-out period has expired, the data is no longer available, and ColdFusion returns
a data-expired exception to the browser; in this case, the browser typically tells the user to reload the page.
If the time-out has not expired, the browser displays the original data.
If your form data contains sensitive information, such as credit card numbers or social security numbers, leave the
time-out set to 0. Otherwise, consider setting a time-out value that corresponds to a small number of minutes.
783
The XSLT skin tells ColdFusion how to process the XML, and typically converts it to HTML for display. The skin
specifies the CSS style sheet to use to format the output.
The CSS style sheet specifies style definitions that determine the appearance of the generated output.
XSLT skins give you extensive freedom in the generated output. They let you create a custom appearance for your
forms, or even different appearances for different purposes. For example, you could use the same form in an intranet
and on the Internet, and change only the skin to give a different appearance (or even select different subsets of the form
for display). You can also create skins that process your form for devices, such as wireless mobile devices.
784
the same name as the form. ColdFusion ignores inline text or HTML tags in the form, and does not pass them to
the XML. (It does process HTML option tags that are children of a cfselect tag.)
2 Applies an XSLT skin to the XML; for example, to convert the form into HTML. The XSLT file specifies the CSS
style sheet.
3 Returns the resulting, styled, form to the client, such as a users browser.
If you omit the cfform tag skin attribute, ColdFusion uses a default skin.
If you specify skin="none", ColdFusion performs the first step, but omits the remaining steps. Your application must
handle the XML version of the form as needed. This technique lets you specify your own XSL engine, or incorporate
the form as part of a larger form.
basic
basiccss
basiccss_top
beige
blue
default
lightgray
red
silver
The XSLT skin files are located in the cf_webroot\CFIDE\scripts\xsl directory, and the CSS files that they use for style
definitions are located in the cf_webroot\CFIDE\scripts\css directory.
The default skin and the basic skin format forms identically. ColdFusion uses the default skin if you do not specify a
skin attribute in the cfform tag. The default and basic skins are simple skins that use tables for arranging the form
contents. The basic skin uses div and span tags to arrange the elements. The skins with names of colors are like the
basic skin, but make more use of color.
785
These tags are designed so you can develop forms in a hierarchical structure of containers and children. Using this
model, the cfform tag is the master container, and its contents are children containers and controls. Each
cfformgroup tag defines a container that organizes its child elements.
The specific tags and attributes that you use in your form depend on the capabilities of the XSLT skin. You use only
the tag and attribute combinations that the skin supports. If you are using a skin provided by a third party, make sure
that the supplier provides information on the supported attributes.
cfinput with type attribute values of text, button, password, and file
786
cfselect
cfslider
cftextarea
Using other skins: If you use any other skin, some attributes are not supported, or the skin supports custom attributes.
Get the information about the supported attributes from the XSLT skin developer.
hrule
text
html
The hrule type inserts an HTML hr tag, and the text type displays unformatted plain text.
The html type displays HTML-formatted text. You can include standard HTML text markup tags, such as strong, p,
ul, or li, and their attributes. For example, the following text from the Example: a simple skinnable form section
shows how you could use a cfformitem tag to insert descriptive text in a form:
<cfformitem type="html">
<b>We value your input</b>.<br>
<em>Please tell us a little about yourself and your thoughts.</em>
</cfformitem>
Using other skins: If you use any other skin, the supported attributes and attribute values depend on the skin
implementation. Get the information about the supported attributes and attribute values from the XSLT skin
developer.
horizontal
vertical
fieldset
The horizontal and vertical types arrange their child tags in the specified direction and place a label to the left of
the group of children. The following text from the Example: a simple skinnable form section shows how you could use
a cfformgroup tag to apply a Name label and align first and last name fields horizontally:
787
The fieldset type corresponds to the HTML fieldset tag, and groups its children by drawing a box around them
and replacing part of the top line with legend text. To specify the legend, use the label attribute. To specify the box
dimensions, use the style attribute with height and width values.
The following code shows a simple form group with three text controls. The cfformgroup type="vertical" tag ensures
that the contents of the form is consistently aligned. The cfformgroup type="horizontal" aligns the firstname and
lastname fields horizontally.
<cfform name="comments" format="xml" skin="basiccss" width="400"
preservedata="Yes" >
<cfformgroup type="fieldset" label="Contact Information">
<cfformgroup type="vertical">
<cfformgroup type="horizontal" label="Name">
<cfinput type="text" size="20" name="firstname" required="yes">
<cfinput type="text" size="25" name="lastname" required="yes">
</cfformgroup>
<cfinput type="text" name="email" label="E-mail" validation="email">
</cfformgroup>
</cfformgroup>
</cfform>
Note: Because XML is case-sensitive, but ColdFusion is not, ColdFusion converts cfformgroup and cfformitem
attributes to all-lowercase letters. For example, if you specify cfformgroup type="Random", ColdFusion converts the
type to random in the XML.
Using other skins: If you use any other skin, the supported attributes and attribute values depend on the skin
implementation. Get the information about the supported attributes and attribute values from the skin developer.
788
URL
Used for
html
http://www.w3.org/1999/xhtml
Form tag information, including action, height, width, and name. XHTML
compliant.
789
Prefix
URL
Used for
xf
http://www.w3.org/2002/xforms
XForms model (including initial field values) and XForms elements that
correspond to cfform tags.
ev
http://www.w3.org/2001/xml-events
cf
XML structure
For each CFML tag, ColdFusion converts attributes and element values to XML in the XForms xf:model element, or
in individual control elements, such as the XForms xf:input, xf:secret, or xf:group elements.
ColdFusion generates XForms XML in the following format. The numbers on each line indicate the level of nesting of
the tags.
1
2
3
4
3
3
3
3
3
3
2
2
2
form tag
XForms model element
XForms instance element
cf:data element
XForms submission element
XForms bind element
XForms bind element
.
.
.
(end of model element)
XForms or ColdFusion extension control element
XForms or ColdFusion extension control element
.
.
.
(end of form)
Data model
The XForms data model specifies the data that the form submits. It includes information on each displayed control
that can submit data, including initial values and validation information. It does not contain information about
cfformgroup or cfformitem tags. The data model consists of the following elements and their children:
790
The body of each element contains the initial control data from the CFML tags value attribute or its equivalent. For
example, for a cfselect tag, the xf:instance element body is a comma-delimited list that contains the name
attributes of all the option tags with a selected attribute. For submit and image buttons, the body contains the name
attribute value.
The following example shows the xf:instance element for the form shown in the image in About XML skinnable
forms on page 783:
<xf:instance>
<cf:data>
<firstname/>
<lastname/>
<email/>
<revision>Comment Form revision 12a</revision>
<satisfaction>very satisfied</satisfaction>
<thoughts>We really want to hear from you!</thoughts>
</cf:data>
</xf:instance>
xf:submission element
The xf:submission element specifies the action when the form is submitted, and contains the values of the
cfformaction and method attributes.:
The following example shows the XML for the form shown in the image in About XML skinnable forms on page 783:
<xf:submission action="/_MyStuff/phase1/forms/XForms/FrameExamples/Figure1.cfm"
method="post"/>
xf:bind elements
The xf:bind elements provide information about the input control behavior, including the control type and any data
validation rules. The XML has one bind element for each instance element that can submit data. It does not have bind
elements for controls such as cfformitem tags, or cfinput tags with submit, input, reset, or image types. Each element
has the following attributes:
Attribute
Description
id
nodeset
XPath expression with the path in the XML to the instance element for the control
required
Each xf:bind element has an xf:extension element with ColdFusion specific information, including type and
validation values. The following table lists the cf namespace elements that are used here.
Element
Description
cf:attribute name="type"
cf:attribute name="onerror"
cfargument name="maxlength"
791
Element
Description
cf:validate type="valiadationtype"
cf:argument
Has one attribute, name, and body text. Each cf:validate element can have
multiple cf:argument children, corresponding to the validation-related
CFML tag attribute values, such as maximum length, and maximum and
minimum range values. The element body contains the CFML attribute value.
Valid name values are as follows. Unless specified otherwise, the name is
identical to the corresponding CFML tag attribute name.
cf:trigger
max
message
min
pattern
onBlur
onSubmit
onServer
The following example shows the xf:bind element of the form shown in the image in About XML skinnable forms
on page 783:
792
<xf:bind id="firstname"
nodeset="//xf:model/xf:instance/cf:data/firstname"
required="true()">
<xf:extension>
<cf:attribute name="type">TEXT</cf:attribute>
<cf:attribute name="onerror">_CF_onError</cf:attribute>
</xf:extension>
</xf:bind>
<xf:bind id="lastname"
nodeset="//xf:model/xf:instance/cf:data/lastname"
required="true()">
<xf:extension>
<cf:attribute name="type">TEXT</cf:attribute>
<cf:attribute name="onerror">_CF_onError</cf:attribute>
</xf:extension>
</xf:bind>
<xf:bind id="email"
nodeset="//xf:model/xf:instance/cf:data/email" required="false()">
<xf:extension>
<cf:attribute name="type">TEXT</cf:attribute>
<cf:attribute name="onerror">_CF_onError</cf:attribute>
</xf:extension>
</xf:bind>
<xf:bind id="satisfaction"
nodeset="//xf:model/xf:instance/cf:data/satisfaction"
required="false()">
<xf:extension>
<cf:attribute name="type">SELECT</cf:attribute>
<cf:attribute name="onerror">_CF_onError</cf:attribute>
</xf:extension>
</xf:bind>
<xf:bind id="thoughts"
nodeset="//xf:model/xf:instance/cf:data/thoughts" required="false()">
<xf:extension>
<cf:attribute name="type">TEXT</cf:attribute>
<cf:attribute name="onerror">_CF_onError</cf:attribute>
</xf:extension>
</xf:bind>
Control elements
The XML tags that follow the xf:bind element specify the form controls and their layout. The XML includes one
element for each form control and cfformitem or cfformgroup tag.
CFML to XML tag mapping
ColdFusion maps CFML tags to XForms elements and ColdFusion extensions as the following table shows:
CFML tag
XML tag
cfinput type="text"
xf:input
cfinput type="password"
xf:secret
cfinput type="hidden"
cfinput type="file"
xf:upload
793
CFML tag
XML tag
cfinput type="radio"
xf:select1
cfinput type="checkbox"
xf:select
cfinput type="button"
xf:trigger
cfinput type="image"
xf:submit
cfinput type="reset"
xf:submit
cfinput type="submit"
xf:submit
cfselect multiple="false"
xf:select1
cfselect multiple="true"
xf:select
cftextarea
xf:textarea
cfslider
xf:range
cfgrid
cf:grid
cftree
cf:tree
cfformitem type="text"
xf:output
cfformitem type="html"
xf:output
xf:group appearance="*"
cfformgroup type="*"
xf:group appearance="*"
ColdFusion converts cfformitem tags with text and html type attributes to XForms output elements with the tag
body in a <![CDATA[ section. It converts all other cfformitem tags to XForms group elements, and sets each
elements appearance attribute to the cfformitem tags type attribute. The XSLT must process these elements to
produce meaningful output. For example, the ColdFusion default skin transform displays the xf:output text blocks
and processes the xf:groupappearance="hrule" element, but it ignores all other xf:group elements.
General control element structure
Each control element that a standard XForms control element can represent has the following general structure.
<xf:tagname bind="bindid" id="bindid">
<xf:label>label</xf:label>
<xf:extension>
<cf:attribute name="type">controltype</cf:attribute>
<cf:attribute name="attribname>attribvalue</cf:attribute>
<cf:attribute name="attribname>attribvalue</cf:attribute>
.
.
.
</xf:extension>
</xf:tagname>
794
Part
Description
tagname
The xf or cf namespace element name, as identified in the table in CFML to XML tag mapping on page 792.
bindid
ID attribute of the model xf:bind element for this control. Specified by the controls CFML tag name attribute.
label
controltype
The value attribute of the radiobutton, radio, submit, and resetcfinput tags
Select, slider, or textarea, for the cfselect, cfslider, or cftextarea tags, respectively.
attribname
Name of a CFML tag attribute. There is a cf:attribute tag for each attribute specified in the CFML code that
does not otherwise have an entry in the XML.
attribvalue
Selection tags
Tags that are used for selection, cfselect, cfinputtype="radio", and cfinputtype="checkbox" are converted to
XForms select and select1 elements. These elements include an xf:choices element, which in turn has an
xf:item element for each item a user can choose. Each item normally has an xf:label element and an xf:value
element. Check boxes have a single item; select and radio button controls have more than one.
The following example shows the CFML code for a group of two radio buttons, followed by the generated XML control
elements. This example also shows the use of a cfformgroup tag to arrange and label the radio button group.
CFML
<cfformgroup type="horizontal" label="Accept?">
<cfinput type = "Radio" name = "YesNo" value = "Yes" checked>
<cfinput type = "Radio" name = "YesNo" value = "No">
</cfformgroup>
795
XML
<xf:group appearance="horizontal">
<xf:label>Accept?</xf:label>
<xf:extension/>
<xf:select1 appearance="full" bind="YesNo" id="YesNo">
<xf:extension>
<cf:attribute name="type">radio</cf:attribute>
</xf:extension>
<xf:choices>
<xf:item>
<xf:label>Yes</xf:label>
<xf:value>Yes</xf:value>
<xf:extension>
<cf:attribute name="checked">checked</cf:attribute>
</xf:extension>
</xf:item>
<xf:item>
<xf:label>No</xf:label>
<xf:value>No</xf:value>
<xf:extension/>
</xf:item>
</xf:choices>
</xf:select1>
</xf:group>
cfgrid tags
ColdFusion represents a cfgrid tag using the cf:grid XML tag. This tag has four attributes: format, which can be
Flash, Applet, or XML; and the id, name, and bind attributes, which all have the value of the cfgrid tag name attribute.
For applet and Flash format grids, ColdFusion inserts cfgrid controls in the XML as HTML embed objects in
<![CDATA[ sections in the body of a cf:grid tag. The controls can be Java applets or in SWF file format.
For XML format grids, ColdFusion converts the CFML to XML in the following format:
796
XML
Most metadata lines are omitted for brevity:
797
798
XML
The following code shows only the XML that is related to the tree appearance:
<cf:tree format="xml" id="tree1">
<metadata>
<fontWeight/>
<align/>
<lookAndFeel>windows</lookAndFeel>
<delimiter>\</delimiter>
<completePath>false</completePath>
<border>false</border>
<hScroll>false</hScroll>
<vScroll>false</vScroll>
<appendKey>true</appendKey>
<highlightHref>true</highlightHref>
<italic>false</italic>
<bold>false</bold>
</metadata>
<node display="Divisions" expand="true" href="" img=""
imgOpen="" parent="" path="Divisions" queryAsRoot="true"
value="Divisions">
<node display="Development" expand="true" href=""
img="folder" imgOpen="" parent="Divisions"
path="Divisions\Development" queryAsRoot="true"
value="Development"/>
</node>
</cf:tree>
799
XML
<xf:output><![CDATA[Please tell us a little about yourself and your
thoughts.]]>
<xf:extension>
<cf:attribute name="style">color:green</cf:attribute>
</xf:extension>
</xf:output>
<xf:group appearance="hrule">
<xf:extension>
<cf:attribute name="width">200</cf:attribute>
<cf:attribute name="height">3</cf:attribute>
<cf:attribute name="testattribute">testvalue</cf:attribute>
</xf:extension>
</xf:group>
800
<xf:group appearance="horizontal">
<xf:label>name</xf:label>
<xf:extension/>
<xf:input bind="firstname" id="firstname">
<xf:label>First</xf:label>
<xf:extension>
<cf:attribute name="type">text</cf:attribute>
<cf:attribute name="size">20</cf:attribute>
</xf:extension>
</xf:input>
<xf:input bind="lastname" id="lastname">
<xf:label>Last</xf:label>
<xf:extension>
<cf:attribute name="type">text</cf:attribute>
<cf:attribute name="size">25</cf:attribute>
</xf:extension>
</xf:input>
</xf:group>
<xf:input bind="email" id="email">
<xf:label>Email</xf:label>
<xf:extension>
<cf:attribute name="type">text</cf:attribute>
<cf:attribute name="validation">email</cf:attribute>
</xf:extension>
</xf:input>
<xf:output><![CDATA[<b>We value your input</b>.<br>
<em>Please tell us a little about yourself and your thoughts.</em>]]>
<xf:extension/>
</xf:output>
<xf:group appearance="vertical">
<xf:extension/>
<xf:select1 appearance="minimal" bind="satisfaction" id="satisfaction">
<xf:label>Satisfaction</xf:label>
<xf:extension>
<cf:attribute name="type">select</cf:attribute>
<cf:attribute name="style">width:200</cf:attribute>
</xf:extension>
<xf:choices>
<xf:item>
<xf:label>very satisfied</xf:label>
<xf:value>very satisfied</xf:value>
</xf:item>
<xf:item>
<xf:label>somewhat satisfied</xf:label>
<xf:value>somewhat satisfied</xf:value>
</xf:item>
<xf:item>
<xf:label>somewhat dissatisfied</xf:label>
<xf:value>somewhat dissatisfied</xf:value>
</xf:item>
<xf:item>
<xf:label>very dissatisfied</xf:label>
<xf:value>very dissatisfied</xf:value>
</xf:item>
<xf:item>
<xf:label>no opinion</xf:label>
<xf:value>no opinion</xf:value>
801
</xf:item>
</xf:choices>
</xf:select1>
<xf:textarea bind="thoughts" id="thoughts">
<xf:label>Additional Comments</xf:label>
<xf:extension>
<cf:attribute name="type">textarea</cf:attribute>
<cf:attribute name="rows">5</cf:attribute>
<cf:attribute name="cols">40</cf:attribute>
</xf:extension>
</xf:textarea>
</xf:group>
<xf:group appearance="horizontal">
<xf:extension/>
<xf:submit id="submit" submission="comments">
<xf:label>Tell Us</xf:label>
<xf:extension>
<cf:attribute name="type">submit</cf:attribute>
<cf:attribute name="name">submit</cf:attribute>
</xf:extension>
</xf:submit>
<xf:submit id="reset">
<xf:label>Clear Fields</xf:label>
<reset ev:event="DOMActivate"/>
<xf:extension>
<cf:attribute name="name">reset</cf:attribute>
</xf:extension>
</xf:submit>
</xf:group>
802
Format
Location
Note: Hosting companies sometimes move the default skin location folder out of CFIDE. Doing this lets them secure the
CFIDE while giving site developers access to the files that you need for cfform.
Description
default.xsl
The default transform that ColdFusion uses if you do not specify a skin attribute for an XML format form.
Identical to the basic.xsl file.
basic.xsl
basiccss.xsl
A basic form format that arranges form elements using HTML div and span tags.
colorname.xsl
A basic form format that arranges form elements using a table and applies a color scheme determined by
the colorname to the form. Based on the basic.xsl file.
_cfformvalidation.xsl
_formelements.xsl
Transformation rules for form elements except for those defined using cfformgroup tags. Used by all
skins
_group_type.xsl
Transformation rules for cfformgroup tags. The tag type attribute is part of the filename. Files with table
in the name are used by basic.xsl and its derivatives. Files with css in the name are used by basiccss.xsl.
_group_type_table.xsl
_group_type_css.xsl
803
All skins support the same set of CFML tags and tag types, and do a relatively simple transformation from XML to
HTML. For example, they do not support horizontal or vertical rules.
The ColdFusion skin XSL files have several features that you can use when designing and developing your own
transformation. They do the following:
Provide an overall structure and initial templates for implementing custom transformations.
Show how you can handle the various elements in the ColdFusion-generated XML.
Use a structure of included files that can form a template for your XSLT code.
The base XSL files include a separate file, _cfformvalidation.xsl, with complete code for generating the hidden fields
required for ColdFusion onServer validation and the JavaScript for performing ColdFusion onSubmit and onBlur
validation. You can include this file without modification to do ColdFusion validation in your XSLT template, or
you can change it to add other forms of validation or to change the validation rules.
The base XSL files include files, that implement several form groups, laying out the child tags and applying a label
to the group. These files can serve as templates for implementing additional form group types or you can expand
them to provide more sophisticated horizontal and vertical form groups.
You can add custom cfformgroup and cfformitemtype attributes by including additional XSL files.
Extending basic.xsl cfformgroup and cfformitem support
The following procedure describes the steps for extending the basic.xsl file to support additional cfformgroup and
cfformitem types. You can use similar procedures to extend other xsl files.
Add support for cfformgroup and cfformitem types to the basic.xsl
1 Create an XSL file.
2 For each type attribute that you want to support, create an xsl:template element to do the formatting. The match
For example, to add a panel cfformgroup type, add an element with a start tag such as the following:
<xsl:template match="xf:group[@appearance='panel']">
a my_group_panel.xsl file to handle a panel cfformgroup type, your basic.xsl file would include the following lines:
<!-- include
<xsl:include
<xsl:include
<xsl:include
<xsl:include
804
File
Description
basic_style.css
Provides a plain style for ColdFusion XSL files that use table-based formatting. These files are identical and
are used by the basic.xsl and default.xsl transforms. ColdFusion uses the default_style.css if you do not
specify a skin in your cfform tag.
default_style.css
basic2_style.css
The basic_style with limited positioning changes for use with XSL files that have div-based formatting.
Used by the basiccss.xsl transform.
css_layout.css
Style specifications for laying out forms that use div-based formatting. Used by the basiccss.xsl transform.
colorname_style.css
Used by the color-formatted ColdFusion skins. Defines the same classes as basic_style.css, with additional
property specifications.
The ColdFusion XSL files and their corresponding CSS style sheets use classes extensively to format the form. The
basic.xsl file, for example, has only one element style; all other styles are class-based. Although the CSS files contain
specifications for all classes used in the XSL files, they do not always contain formatting information. The horizontal
class definition in basic_style.css, which is used for horizontal form groups, for example, is empty.
You can enhance the style of XML skinnable forms without changing the XSL transform by enhancing the style sheets
that ColdFusion provides.
805
ColdFusion supports data binding in many tags. Binding allows form and display tags to dynamically display
information based on form input. In the simplest application, you display form data directly in other form fields.
But usually, you pass form field data as parameters to CFC or JavaScript functions or CFM pages, and use the results
to control the display.
The cfajaximport tag specifies the location of the JavaScript and CSS files that a ColdFusion page imports or to
selectively import files required by specific tags. The ability to change the file location lets you support a wide range
of configurations and use advanced techniques, such as application-specific styles.
For more information about the data and development features and how to use them, see Using Ajax Data and
Development Features on page 858.
User Interface tags and features
Several ColdFusion user interface elements incorporate Ajax features. The tags and tag-attribute combinations can be
divided into the following categories:
Description
Container tags
cfdiv
An HTML div region that can be dynamically populated by a bind expression. Forms
in this region submit asynchronously.
cflayout
A horizontal or vertical box, a tabbed region, or a set of bordered regions that can
include a top, bottom, left, right, and center regions.
cflayoutarea
An individual region within a cflayout area, such as the display that appears in a
tabbed layout when the user select a tab. Forms in this region submit asynchronously.
cfpod
An area of the browser window with an optional title bar and a body that contains
display elements. Forms in this region submit asynchronously.
cfwindow
A pop-up window within the browser. You can also use the
ColdFusion.Window.createWindow function to create a pop-up window. Forms
in this region submit asynchronously.
Forms tags
806
Tag/attribute
Description
cfgrid format="html"
cfinput type="datefield"
An input control that users can fill by selecting a date from a pop-up calendar.
cftextarea richtext="yes"
A text area with a set of controls that let users format the displayed text.
cftree format="html"
cfslider
A slider control, for selecting a numeric value from a range, in a ColdFusion form.
Menu tags
cfmenu
cfmenuitem
A drop-down autofill suggestion box. As the user types, a list appears with completion
suggestions based on the text the user has typed.
A textual description of a control or region that appears when the user hovers the
mouse over the control or region.
Other tags
cfprogressbar
cfmap
cfmediaplayer
cfmessagebox
In addition to the tags and attributes, ColdFusion provides many JavaScript functions that let you control and manage
the display. Many functions control the display of specific tags. For example, you can use JavaScript functions to
dynamically display and hide the window. There are also several utility tags, such as the
ColdFusion.getElementValue function that gets the value of a control attribute, or the ColdFusion.navigate
function that displays the results of a URL in a container tag. For a complete list of all ColdFusion Ajax JavaScript
functions, and detailed function descriptions, see Ajax JavaScript Functions in the CFML Reference.
Display layout
Data interaction
Display layout controls include the cflayout, cfpod, and cfwindow controls. Some of the data interaction features
include the HTML cfgrid control, the cfmenu control, and dynamic autosuggest lists for text input controls. Most
display layout and data interaction features can use data binding to dynamically interact with the user.
807
ColdFusion Ajax user interface features are based on the Yahoo User Interface Library and the Ext JavaScript Library.
Also, the cftextarea rich text editor is based on the FCKeditor text editor. In most situations, you require only
ColdFusion tags and functions (including JavaScript functions) to create and manage the interface. However,
advanced developers can modify the library code, particularly the CSS styles, to customize the controls in more
complex ways.
cfdiv
cflayout
cfpod
cfwindow
For information about how you can use these tags to submit form contents asynchronously, see Using Ajax containers
for form submission on page 820.
808
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>cfdiv Example</title>
</head>
<body>
<cfform>
<cfinput name="tinput1" type="text">
</cfform>
<h3> using a div</h3>
<cfdiv bind="url:divsource.cfm?InputText={tinput1}" ID="theDiv"
style="background-color:##CCffFF; color:red; height:350"/>
</body>
</html>
The divsource.cfm file that defines the contents of the div region has the following code:
<h3>Echoing main page input:</h3>
<cfoutput>
<cfif isdefined("url.InputText")>
#url.InputText#
<cfelse>
No input
</cfif>
</cfoutput>
Using layouts
The cflayout tag controls the appearance and arrangement of one or more child cflayoutarea regions. The
cflayoutarea regions contain display elements and can be arranged in one of the following ways:
Horizontally or vertically.
In a free-form bordered grid (panel layout) with up to five regions: top, bottom, left. right, and center. You can
optionally configure the layout so that users can resize or collapse any or all of the regions, except the center region.
The center region grows or shrinks to take up any space that other regions do not use. You can also dynamically
show or hide individual regions, or let users collapse, expand, or close regions.
As a tabbed display, where selecting a tab changes the display region to show the contents of the tabs layout area.
You can dynamically show and hide, and enable and disable tabs, and optionally let users close tabs.
You can configure a layout area to have scroll bars all the time, only when the area content exceeds the available screen
size, or never. You can let layout area contents extend beyond the layout area. You can also nest layouts inside layout
areas to create complex displays.
You can define the layout area content in the cflayoutarea tag body. But, you can also use a bind expression to
dynamically get the content by calling a CFC function, requesting a CFML page, or calling a JavaScript function.
ColdFusion provides many JavaScript functions for managing layouts, including functions to collapse, expand, show,
and hide border areas; and to create, enable, disable, select, show, and hide tabs. For a complete list of functions, see
Ajax JavaScript Functions in the CFML Reference.
The following example shows the use of a tabbed layout, including the use of JavaScript functions to enable and disable
a tab, and to show and hide a tab.
809
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<!--- The tabheight attribute sets the height of all tab content areas and therefore the
layout height. The width style controls the layout width. --->
<cflayout type="tab" name="mainTab" tabheight="300px" style="width:400px">
<!--- Each layoutarea is one tab. --->
<cflayoutarea title="First Tab" name="tab1">
<h2>The First Tab</h2>
<p>
Here are the contents of the first tab.
</p>
</cflayoutarea>
<cflayoutarea title="Second Tab" name="tab2">
<h2>The Second Tab</h2>
<p>
This is the content of the second tab.
</p>
</cflayoutarea>
</cflayout>
<p>
Use these links to test selecting tabs via JavaScript:<br />
<a href="" onClick="ColdFusion.Layout.selectTab('mainTab','tab1');return false;">
Click here to select tab 1.</a><br />
<a href="" onClick="ColdFusion.Layout.selectTab('mainTab','tab2');return false;">
Click here to select tab 2.</a><br />
</p>
<p>
Use these links to test disabling/enabling via JavaScript. Notice that you cannot disable
the currently selected tab.<br />
<a href="" onClick="ColdFusion.Layout.enableTab('mainTab','tab1');return false;">
Click here to enable tab 1.</a><br />
<a href="" onClick="ColdFusion.Layout.disableTab('mainTab','tab1');return false;">
Click here to disable tab 1.</a><br />
</p>
</body>
</html>
For an example that uses a bordered layout with cfpod children, see the next section. For another example of a tab
layout, see the cflayoutarea tag in the CFML Reference. For an example of a bordered layout nested inside a layout area
of a vertical layout, see cflayout in the CFML Reference.
810
Styling layouts
The cflayout and cflayoutarea tags have style attributes. The cflayout tag style attribute controls the style of
the layout container, and sets default values for many, but not all, styles for the layout areas. For example, the color and
background color styles of the cflayout tag set the default text and background colors in the layout areas. But the
cflayout tag border style sets only the color of the border around the entire layout, not the layout area borders. The
cflayoutarea tag style attribute controls the style of the individual layout area and overrides any corresponding
settings in the cflayout tag.
As is often the case with complex controls, the effects of layout and layout area styles can vary. For example, do not
often specify the height style in the cflayout tag; instead, specify height styles on each of the cflayoutarea tags.
The following simple example shows a tab layout with two layout areas. The layout has a light pink background color,
and the layout areas have three pixel-wide red borders.:
<cflayout name="layout1" type="tab" style="background-color:##FFCCCC">
<cflayoutarea title="area1" style="border:3px solid red">
Layout area 1
</cflayoutarea>
<cflayoutarea title="area1" style="border:3px solid red">
Layout area 2
</cflayoutarea>
</cflayout>
Using pods
The cfpod control creates a content region with a title bar and surrounding border. You can define the pod content in
the cfpod tag body, or you can use a bind expression to dynamically get the content from a URL. Pods are frequently
used for portlets in a web portal interface and for similar displays that are divided into independent, possibly
interactive, regions.
You control the pod header style and body style independently by specifying CSS style properties in the headerStyle
and bodyStyle attributes.
The following example uses multiple pods inside cflayoutarea tags to create a simple portal. The time pod gets the
current time from a CFML page. The contents of the other pods is defined in the cfpod bodies for simplicity. Each pod
uses the headerStyle and bodyStyle attributes to control the appearance.
The cfpodExample.cfm application has the following code:
811
<html>
<head>
</head>
<body>
<cflayout name="theLayout" type="border" style="height:300;">
<cflayoutarea position="left" size="300" style="float:right;">
<cfpod width="300" name="theNews" title="All the latest news"
headerstyle="background-color:##DDAADD; font-size:large;
font-style:italic; color:black"
bodyStyle="background-color:##FFCCFF; font-family:sans-serif;
font-size:80%">
Contents of a news feed would go here.
</cfpod>
</cflayoutarea>
<cflayoutarea position="center" align="center" >
<cfpod name="theSports" width="500"
title="What's new in your favorite sports"
headerstyle="background-color:##AADDDD; font-size:large;
font-style:italic; color:black"
bodyStyle="background-color:##CCFFFF; font-family:sans-serif;
font-size:90%">
Contents of a sports feed would go here.
</cfpod>
</cflayoutarea>
<cflayoutarea position="right" size="302">
<cfpod width="300" height="20" name="thetime" title="The Weather"
source="podweather.cfm"
headerstyle="background-color:##DDAADD; font-style:italic;
color:black"
bodyStyle="background-color:##FFCCFF; font-family:sans-serif;
font-size:80%" />
<cfpod width="300" name="thestocks" title="What's new in business"
headerstyle="background-color:##DDAADD; font-size:large;
color:black; font-style:italic"
bodyStyle="background-color:##FFCCFF; font-family:sans-serif;
font-size:80%">
Contents of a news feed would go here.
</cfpod>
</cflayoutarea>
</cflayout>
</body>
</html>
In this example, the podweather.cfm page contains only the following line. A more complete example would
dynamically get the weather from a feed and format it for display.
Partly Cloudy, 76 degrees
812
They can be modal (users cannot interact with the main window when the pop-up window is displayed) or nonmodal (users can interact with both windows).
You can specify that the user can drag, close, or resize the window.
You can create and show a window independently. After you create the window, you can use JavaScript functions
to show and hide it multiple times without having to create it again.
Display and hide windows
You display a window in the following ways:
By using a ColdFusion cfwindow tag with an initShow attribute value of to create and show the window.
By using a ColdFusion cfwindow tag with an initShow attribute value of false and calling the
ColdFusion.Window.show JavaScript function to display it.
813
<form>
<!--- Use the API to show and hide Window 1. --->
<input type="button" value="Show Window1"
onClick="ColdFusion.Window.show('window1')">
<input type="button" value="Hide Window1"
onClick="ColdFusion.Window.hide('window1')"><br />
<!--- Use the API to create, show, and hide Window 2 --->
<input type="button" value="Create Window2"
onClick="ColdFusion.Window.create('window2', 'JavaScript Window',
'window2.cfm', config)">
<input type="button" value="Show Window2"
onClick="ColdFusion.Window.show('window2')">
<input type="button" value="Hide Window2"
onClick="ColdFusion.Window.hide('window2')">
</form>
</body>
</html>
The window2.cfm file with the contents of Window 2 has the following contents:
<cfoutput>
<p>
This content was loaded into window 2 from a URL.<br />
</p>
</cfoutput>
814
<html>
<head>
<script language="javascript">
//Boolean value tacking the window state.
var shown=true;
//Functions to display an alert box when
function onshow(name) {
alert("window shown = " + name);
}
function onhide(name) {
alert("window hidden = " + name);
}
//Initialize the window show/hide behavior.
function initWindow() {
ColdFusion.Window.onShow("testWindow", onshow);
ColdFusion.Window.onHide("testWindow", onhide);
}
//Show or hide the window, depending on its current state.
function toggleWindow() {
if (shown) {
ColdFusion.Window.hide("testWindow");
shown = false;
}
else {
ColdFusion.Window.show("testWindow");
shown = true;
}
}
</script>
</head>
<!-- The body tag onLoad event calls the window show/hide initializer function. -->
<body onLoad="initWindow()">
<cfwindow name="testWindow" initshow=true title="test window" closable=true> Window contents
</cfwindow>
<cfform>
<cfinput name="button" value="Toggle Window" onclick="javascript:toggleWindow()"
type="button"/>
</cfform>
</body>
</html>
You can use bind expressions in the container tag source (or for cfdiv, bind) attribute. The container then
dynamically updates any time a bound control changes.
You can call the ColdFuson.navigate function to change the container body to be the contents returned by a
specified URL. This function lets you specify a callback handler to do additional processing after the new content
loads, and also lets you specify an error handler.
815
The callback handler can be useful to provide information about a successful navigation operation. For example,
you could make a pod's title bar italic to indicate loading (just before the navigate call), and use the callback handler
to switch it back to normal once the navigate completes. Similarly, if a pod is showing pages from a book, the
callback handler could update a page number in a separate field once a page loads
You can use the special controlName_body variable to access and change the body contents for cfpod and
cfwindow controls. For example, you can use the controlName_body.innerHTML property to set the body HTML.
For cfpod and cfwindow tags, you can also use the controlName_title to get or set the title bar contents of the
control.
These different techniques provide you with flexibility in writing your code. For example, the ColdFuson.navigate
function and the controlName_body variable provide similar functionality. However, with the controlName_body
technique, you make explicit Ajax requests to get markup for the body, and the JavaScript functions in the retrieved
markup might not work properly. ColdFusion.navigate takes care of these issues. Therefore, limit use of the
controlName_body technique to simpler use cases.
The following example shows how you can use various techniques to change container contents. It consists of a main
page and a second windowsource.cfm page with text that appears in a main page window when you click a button. The
main page has a cfpod control, two cfwindow controls, and the following buttons:
The Simple navigate button calls a ColdFusion.navigate function to change the contents of the second
window.
The Change w2 body & title button replaces the second windows body and title innerHTML values directly to
specific strings.
The Change pod body button changes the pod body innerHTML to the value of the second windows title
innerHTML.
The following example shows the main page:
<html>
<head>
<!--- Callback handler puts text in the window.cfm callback div block. --->
<script language="javascript">
var mycallBack = function(){
document.getElementById("callback").innerHTML = "<br><br>
<b>This is printed by the callback handler.</b>";
}
<!--- The error handler pops an alert with the error code and message. --->
var myerrorHandler = function(errorCode,errorMessage){
alert("[In Error Handler]" + "\n\n" + "Error Code: " + errorCode + "\n\n" +
"Error Message: " + errorMessage);
}
</script>
</head>
<body>
<cfpod height="50" width="200" title="The Title" name="theTitle">
This is a cfpod control.
</cfpod><br>
<!--- Clicking the link runs a ColdFusion.navigate function that replaces the second window's
contents with windowsource.cfm. The callback handler then updates the window
contents further. --->
<cfwindow name="w1" title="CF Window 1" initShow=true
x=10 y=200 width="200">
816
Menus can have submenus, but only the top menu can be horizontal. All children of a horizontal menu are vertical.
The top-level menu shows initially, a submenu shows when the user moves the mouse over the menu root in the
parent menu.
A horizontal menu has dividers between all items. You place dividers in vertical menus by specifying a cfmenuitem
tag with a divider attribute.
To make a menu item active, specify a href attribute with a URL or a JavaScript function to call when the user clicks
the menu item.
817
The following example shows a simple horizontal menu with submenus that uses JavaScript to change the display
contents. When the user selects an end item in a menu, the text in the div block below the menu shows the path to the
selected menu.
<html>
<head>
</head>
<body>
<!--- The selected function changes the text in the selectedItemLabel div block to show the
selected item. --->
<script type="text/javascript">
function selected(item) {
var el = document.getElementById("selectedItemLabel");
el.innerHTML = "You selected: " + item;
}
</script>
<!--- A horizontal menu with nested submenus. Clicking an end item calls the selected
function. --->
<cfmenu name="hmenu" bgcolor="##9999ff" selectedfontcolor="##0000dd"
selecteditemcolor="##ddddff">
<cfmenuitem display="Home" href="javascript:selected('Home');" />
<cfmenuitem display="File">
<cfmenuitem display="Open...">
<cfmenuitem display="Template" href="javascript:selected('File >
Open... > Template');" />
<cfmenuitem divider="true" />
<cfmenuitem display="CSS" href="javascript:selected('File > Open... >
CSS');" />
</cfmenuitem>
<cfmenuitem display="Close" href="javascript:selected('File > Close');" />
</cfmenuitem>
<cfmenuitem display="Help">
<cfmenuitem display="About" href="javascript:selected('Help > About');" />
</cfmenuitem>
</cfmenu>
<!--- A div with initial text.
The selected function changes the text by resetting the innerHTML. --->
<div style=" margin-top: 100; margin-left: 10;"><span id="selectedItemLabel">
Please select an item!</span></div>
</body>
</html>
Styling menus
The cfmenu and cfmenuitem tags have several attributes that let you easily control the menu appearance. These
attributes consist of two types: basic and CSS style. Basic attributes, such as the cfmenu tag fontColor attribute,
control individual menu characteristics. CSS style attributes let you specify a CSS style specification for a whole menu
or part of a menu. The following information describes how the CSS style specifications interact and affect the menu
style. For descriptions of all style-related attributes, see the cfmenu and cfmenuitem descriptions in the CFML
Reference.
818
The cfmenu and cfmenuitem tags provide a hierarchy of CSS style attributes that affect different parts of the menu.
The following table describes these attributes in hierarchical order:
Attribute
Description
cfmenu attributes
menuStyle
Applies to the menu, including any parts of the menu that surround the menu items. If you do not
override this style in a cfmenu tag childStyle attribute or by specifying style information in the
cfmenuitem tags, this attribute controls the style of the top-level items.
childStyle
Applies to the items in the top level menu and all child menu items, including the children of submenus.
This attribute lets you use a single style specification for all menu items.
cfmenuitem attributes
style
Applies to the current menu item only. It is not overridden by the childStyleattribute.
menuStyle
Controls the overall style of any submenu of this menu item. This attribute controls the submenu of the
current menu item, but not to any child submenus of the submenu.
childStyle
Applies to all child menu items of the current menu item, including the children of submenus.
In addition to these styles, consider any style-related attributes, such as bgcolor, that you set on the cfmenu tag.
When you design your menu, keep in mind the following issues:
Keep font sizes at 20 pixels or smaller. Larger sizes can result in menu text in vertical menus exceeding the menu
boundaries.
Consider how the style attributes interact. Because each menu and submenu consists of a surrounding menu area
and individual child items, be careful when you choose background colors. For example, if you specify different
background-color styles in the cfmenu tags menuStyle and childStyle attributes, the menu items are one color
and the surrounding menu area are a different color.
For an application that shows some of the effects of menu style attributes, see the example in the cfmenuitem tag in
the CFML Reference.
ColdFusion attributes provide most style options that you are likely to require. However, you can, if necessary, modify
the basic menu styles for all menus by editing the menu-related styles in the CSS files in the yui.css file. This file is
located by default in the web_root/CFID/scripts/ajax/resources/yui directory. For more information about these styles,
see the Yahoo! User Interface Library menu documentation.
Uploading files
The cffileupload tag lets you select multiple files and upload them to a server.
Uses callback and error handlers that lets provides control over file upload process after upload completion or if
errors occur.
819
If the user tries to upload a file already present in the upload directory, it results in an error. The status and message
are set to the specifications in the catch block.
Using styles
The attributes headercolor, textcolor, bgcolor, titletextalign, titletextcolor, and rollovercolor lets
you style the file upload control.
The following example illustrates the styling of file upload control:
<cffileupload
url="uploadAll.cfm"
name="myuploader3"
align="right"
style="headercolor:silver;textcolor:1569C7;titletextalign:right;titletextcolor:black;bgcolor
:74BBFB;"/>
820
The cfgrid, cfinput, cfselect, cftextarea, and cftree controls support binding to get control contents.
ColdFusion functions support asynchronous submission of forms without refreshing the entire page. When a form
is in an Ajax container control, it is done automatically. Also, the ColdFusion.Ajax.SubmitForm JavaScript
function and Ajax proxy setForm function support manual asynchronous submissions.
The cfgrid and cftree tags provide HTML grids and trees that do not require a Java applet or Flash.
The cftextarea control has a rich text editor option. The text editor is configurable.
The cfinput tag supports a datefield type with an Ajax-based pop-up calendar from which user can select the date.
The cfinput tag with text type supports an autosuggest attribute that lets you dynamically supply a drop-down
list of field completions based on the current user input.
The cfinput, cfselect, and cftextarea tags support a tooltip attribute that specifies a pop-up tool tip to
display when the user moves the mouse over the control. The cftooltip tag displays a tool over any region of a
page, not just a form control.
821
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<cflayout type="vbox" name="layout1">
<cflayoutarea>
<h3>This area is not refreshed when the form is submitted.</h3>
<br />
</cflayoutarea>
<cflayoutarea>
<h3>This form is replaced by the action page</h3>
<cfform name="myform" format="html" action="showName.cfm">
<cfinput type = "Text" name = "name">
<cfinput type = "submit" name = "submit" value = "Enter name">
</cfform>
</cflayoutarea>
</cflayout>
</body>
</html>
In the following example, when you enter a name in the text input and click the Enter name button, the entered text
replaces the form on the page, but the rest of the page is not refreshed. This example shows the showName.cfm action page:
<cfif IsDefined("Form.name")>
<cfoutput>The Name is : <strong>#Form.name#</strong></cfoutput>
</cfif>
The function does not need to specify the form fields in cfargument tags, and the function gets the field values
passed by name.
Form fields that have the same names as CFC arguments override the CFC argument values.
If you do not specify form fields in the cfargument tags, they do not necessarily follow any declared arguments,
when you use positional (array) notation to access them in the arguments structure.
The arguments scope in the CFC function includes two fields that ColdFusion uses to control its behavior. These
fields are intended for internal use, and their names might change in future releases. Both field values are set to
true:
_CF_NODEBUG tells ColdFusion not to return debugging output in the call response.
_CF_NOCACHE tells ColdFusion to send a no cache header on the response, which prevents the browser from
caching the response and ensures that every Ajax request results in a network call.
822
The following example shows how to use the SetForm tag to submit the contents of a login form. When the user clicks
the Login! button, the doLogin function calls the proxy setForm function and then the AuthenticationSystem.cfc
validateCredentials method. The validateCredentials method checks the password of the user and if it is
valid, returns true to the proxy. Because the proxy is synchronous (the default), the doLogin method gets the returned
value. If the value is true, it hides the login window; the user can then access the page contents. If the return value is
false, the doLogin function displays a message in the login window title bar.
The following example shows the setForm.cfm application:
<html>
<head>
<script type="text/javascript">
function doLogin() {
// Create the Ajax proxy instance.
var auth = new AuthenticationSystem();
// setForm() implicitly passes the form fields to the CFC function.
auth.setForm("loginForm");
//Call the CFC validateCredentials function.
if (auth.validateCredentials()) {
ColdFusion.Window.hide("loginWindow");
} else {
var msg = document.getElementById("loginWindow_title");
msg.innerHTML = "Incorrect username/password. Please try again!";
}
}
</script>
</head>
<body>
<cfajaxproxy cfc="AuthenticationSystem" />
<cfif structKeyExists(URL,"logout") and URL.logout>
<cflogout />
</cfif>
<cflogin>
<cfwindow name="loginWindow" center="true" closable="false"
draggable="false" modal="true"
title="Please login to use this system"
initshow="true" width="400" height="200">
<!--- Notice that the form does not have a submit button.
823
824
825
Sort the grid in ascending or descending order based on the columns content.
Select the columns to display.
If the grid has a groupfield attribute: turn grouping off and on and group by the column value.
If you specify selectMode="edit" for an HTML grid, the grid displays Insert, Save, Cancel, and Delete buttons to
the bottom bar. The Insert button opens a new editable row. The Save button commits any changes to the bind source.
The Cancel button rolls back any changes that have not been saved. The Delete button deletes a selected row. You need
not press the Save button after clicking the Delete button.
Dynamically filling form data
HTML grids can dynamically fill the grid data by using a bind attribute with a bind expression that calls a CFC or
JavaScript function, or a URL. The bind expression uses bind parameters to specify dynamic information provided by
the grid and the values of any other form field attributes.
Pass the following bind parameters to the bind expression. If you omit any of the parameters in the function call or
URL, you get an error. These parameters send information about the grid and its state to the data provider function.
The data for these parameters is provided automatically. You do not set any values manually.
Parameter name
Description
cfgridpage
cfgridpagesize
The number of rows of data in the page. The value of this parameter is the value of the pageSize
attribute.
cfgridsortcolumn
The name of the column that determines the sorting order of the grid. This value is set only after the user
clicks a column heading.
cfgridsortdirection
The direction of the sort, may be 'ASC' (ascending) or 'DESC' (descending). This value is set only after the
user clicks a column heading.
Note: The cfgridsortcolumn and cfgridsortdirection parameters can be empty if the user or application has not
sorted the grid, for example, by clicking a grid column header.
For more information on binding and bind parameters, see Using Ajax Data and Development Features on page 858
in the CFML Reference.
You can use optional parameters to specify additional information to pass to the called function. These parameters
provide data that the called function requires to determine the data to return. For example, if the function returns the
cities in a state, you would pass it the state name. Any or all of the optional function parameters can be bind parameters.
A state name, for example, could come from the selection in a states cfselect control.
826
If you do not want the grid to refresh automatically when other controls change, you can use the @none specifier on all
optional bind parameters. Doing this, prevents automatic updating of the grid based on the bound control values. Use
the ColdFusion.Grid.refresh JavaScript function to explicitly refresh the grid contents. For more information on the
use of the @none specifier and explicitly refreshing the control, see Specifying bind parameters on page 861.
If the grid supports user sorting of the data (the sort attribute is true), the function called by the bind expression must
return data in the desired sorted order, and must use the values of the cfgridsortcolumn and
cfgridsortdirection bind parameters to determine the order. Even if you do not allow user sorting, still pass these
parameters to the function; otherwise, you get an error. Also, your function or action page must handle cases where
these parameters are empty strings, because their values are not set until the user selects a column header to sort the
grid, or you call the JavaScript ColdFusion.Grid.sort function.
The format of the returned data depends on how you get the data:
Bind type
Return value
CFC
A ColdFusion structure. ColdFusion automatically converts the structure for return to the caller.
Alternatively, you can return a JSON representation of the structure.
URL
JavaScript
A JavaScript object.
When you specify a CFC in the bind attribute, use the queryConvertForGrid function to convert a query directly
into a structure that you can use as your CFC return value.
When you specify a CFML page in the bind attribute, use the queryConvertForGrid function to convert a query into
a structure, and then use the serializeJSON function to convert the structure into a JSON representation.
If you manually create a JavaScript object or its JSON representation, it must have two top-level keys:
TOTALROWCOUNT: The total number of rows in the query data set being returned. This value is the total number of
rows of data in all pages in the grid, and not the number of rows in the current page.
QUERY: The contents of the query being returned. The QUERY value must also be an object with two keys:
DATA: A two-dimensional array, where the first dimension corresponds to the rows and the second dimension
corresponds to the field values, in the same order as the COLUMNS array.
Note: If a CFC manually creates a return structure, the QUERY value can be a ColdFusion query object; ColdFusion
automatically converts it for remote access.
The following example defines an object that a JavaScript bind function can return to provide the data for a cfgrid tag:
var myobject =
{"TOTALROWCOUNT":6,"QUERY":{"COLUMNS":["EMP_ID","FIRSTNAME",
"EMAIL"],"DATA":[[1,"Carolynn","CPETERSON"],
[2,"Dave","FHEARTSDALE"], [3,"Linda","LSTEWART"],
[4,"Aaron","ASMITH"], [5,"Peter","PBARKEN"],
[6,"Linda","LJENNINGS"],]}};
The following example uses a bind expression and a CFC to populate a dynamic, paged, data grid. The CFML page
contains the following form:
827
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<cfform name="form01">
<cfgrid format="html" name="grid01" pagesize=5 sort=true
bind="cfc:places.getData({cfgridpage},{cfgridpagesize},
{cfgridsortcolumn},{cfgridsortdirection})">
<cfgridcolumn name="Emp_ID" display=true header="eid" />
<cfgridcolumn name="FirstName" display=true header="Name"/>
<cfgridcolumn name="Email" display=true header="Email" />
</cfgrid>
</cfform>
</body>
</html>
The places.cfc file looks as follows. Notice that the query gets the full data set each time the function gets called. the
QueryConvertForGrid function selects and returns only the required page of data:
<cfcomponent>
<cffunction name="getData" access="remote" output="false">
<cfargument name="page">
<cfargument name="pageSize">
<cfargument name="gridsortcolumn">
<cfargument name="gridsortdirection">
<cfquery name="team" datasource="cfdocexamples">
SELECT Emp_ID, FirstName, EMail
FROM Employees
<cfif gridsortcolumn neq "" or gridsortdirection neq "">
order by #gridsortcolumn# #gridsortdirection#
</cfif>
</cfquery>
<cfreturn QueryConvertForGrid(team, page, pageSize)>
</cffunction>
</cfcomponent>
The following example is equivalent to the previous one, but uses a URL bind expression in the main page and a CFML
page to return the data.
The main page contains the following form:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<cfform name="form01">
<cfgrid format="html" name="grid01" pagesize=5 sort=true
bind="url:getdata.cfm?page={cfgridpage}&pageSize={cfgridpagesize}
&sortCol={cfgridsortcolumn}&sortDir={cfgridsortdirection}">
<cfgridcolumn name="Emp_ID" display=true header="eid" />
<cfgridcolumn name="FirstName" display=true header="Name"/>
<cfgridcolumn name="Email" display=true header="Email" />
</cfgrid>
</cfform>
</body>
</html>
828
If your database lets you specify SQL to retrieve only the required page of data in a query, you can optimize efficiency
by using such a query. Do not use the QueryConvertForGrid function. Instead, manually create the return structure
and return only the single page of data. Ensure that you set the TotalRowCount field to the number of rows in the entire
data set, not the number of rows in the returned page of data.
Using the bindOnLoad attribute
The bindOnLoad attribute causes a control to execute its bind expression immediately when it loads, and not wait until
the event that normally triggers the bind expression evaluation to occur. This way, the control can be filled with an
initial value. This attribute is false by default for all ColdFusion Ajax controls that have the attribute, except cfdiv
and cfgrid, for which it is true by default. Having a truebindOnLoad value on these controls ensures that they are
populated when they load.
When a control with a truebindOnLoad attribute is bound to a control that also binds when the page loads, the first
and second control load themselves at the onLoad page event. Then the first control loads itself again in response to a
change event from the second control when that control completes loading. So, the first control makes two Ajax calls,
whereas it must make only one, when the second control finished loading.
Because the cfinput, cfselect, and cftextarea control bindOnLoad attributes are false by default, you do not
encounter any problems if a cfgrid or cfdiv tag binds to any of these controls and you do not explicitly set the
bindOnLoad attributes. However, if the control does set its bindOnLoad attribute to true, set the cfgrid or cfdiv
attribute to false to ensure that the control only fetches data when the control that it is bound to returns.
You can also get a double loading if a grid binds to a Spry data set. By default, the grid and data set load data at page
load, and then the grid loads data again in response to a selection change event from the data set when it sets focus to
its first row. Set bindOnLoad to false to ensure that the grid fetches data only when it receives a selection change
event from the data set.
Dynamically editing grid contents
When you use a bind expression to get cfgrid data dynamically, you can also update the data source dynamically with
user input, without requiring the user to submit the form. You can use dynamic updating to update or delete data in
the data source. (To edit cfgrid data, select the contents of a field and type the new value; to delete a row, select a field
in the row and click the delete button at the bottom of the grid.)
You cannot insert new rows directly in a grid that uses a bind expression. To add rows, enter the data in a form, and
make sure that the grid refreshes after the form has been submitted.
829
Specify selectmode="edit" in the cfgrid tag. This lets the user edit the grid.
Specify an onChange attribute in the cfgrid tag. The attribute must use a bind expression to specify a CFC method,
JavaScript function, or URL of a page that updates the data source. The bind expression has the same format as the
bind expression described in Dynamically filling form data on page 825; however, it must take the following bind
parameters that the grid automatically passes. These parameters send information about the grid and its state to the
onChange function.
Parameter name
Description
cfgridaction
The action performed on the grid. 'U' for update, or 'D' for delete.
cfgridrow
A structure or JavaScript Object whose keys are the column names and values are the original values
of the updated or deleted row.
cfgridchanged
A structure or JavaScript Object with a single entry, whose key is the name of the column with the
changed value, and whose value is the new value of the field. If the grid action is delete, this structure
exists but is empty.
When you update data dynamically, you can also use the onError attribute to specify the name of a JavaScript function
to handle any errors that result in a CFC or URL returning an HTTP error status. The method must take two
parameters: the HTTP error code and a text message that describes the error. The following example shows an
onError handler function:
<script type="text/javascript">
function errorhandler(id,message) {
alert("Error while updating \n Error code: "+id+" \nMessage:
"+message);}
</script>
The following example displays the members of a department and lets users edit the data in the fields. When the focus
leaves the edited field an onChange event triggers and the form calls the editData CFC function to update the data
source.
830
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function errorhandler(id,message) {
alert("Error while updating\n Error code: "+id+"\n Message: "+message);
}
</script>
</head>
<body>
<cfform name="form01">
<cfgrid format="html" name="grid01" pagesize=11
stripeRows=true stripeRowColor="gray"
bind="cfc:places.getData({cfgridpage},{cfgridpagesize},
{cfgridsortcolumn},{cfgridsortdirection})"
delete="yes" selectmode="edit"
onchange="cfc:places.editData({cfgridaction},{cfgridrow},{cfgridchanged})">
<cfgridcolumn name="Emp_ID" display=true header="Employee ID"/>
<cfgridcolumn name="FirstName" display=true header="Name"/>
<cfgridcolumn name="Email" display=true header="Email"/>
</cfgrid>
</cfform>
</body>
</html>
The getData function is identical to the getData function in Dynamically filling form data on page 825. This
example shows the editData function in the CFC:
<cffunction name="editData" access="remote" output="false">
<cfargument name="gridaction">
<cfargument name="gridrow">
<cfargument name="gridchanged">
<cfif isStruct(gridrow) and isStruct(gridchanged)>
<cfif gridaction eq "U">
<cfset colname=structkeylist(gridchanged)>
<cfset value=structfind(gridchanged,#colname#)>
<cfquery name="team" datasource="cfdocexamples">
update employees set <cfoutput>#colname#</cfoutput> =
'<cfoutput>#value#</cfoutput>'
where Emp_ID = <cfoutput>#gridrow.Emp_ID#</cfoutput>
</cfquery>
<cfelse>
<cfquery name="team" datasource="cfdocexamples">
delete from employees where emp_id = <cfoutput>#gridrow.Emp_ID#
</cfoutput>
</cfquery>
</cfif>
</cfif>
</cffunction>
831
By default, each time the selected row in the grid changes, the bind parameter is re-evaluated, and the control value
changes to the value of the specified column of selected grid cell.
Grid JavaScript functions
You can use the following JavaScript functions to manage an HTML format grid:
Function
Description
ColdFusion.Grid.getGridObject
ColdFusion.Grid.refresh
ColdFusion.Grid.sort
832
<cfset querysetcell(emps,"salary","100000",8)>
<cfset querysetcell(emps,"active","false",8)>
<cfset querysetcell(emps,"firstname","Adam",9)>
<cfset querysetcell(emps,"department","CF",9)>
<cfset querysetcell(emps,"salary","300000",9)>
<cfset querysetcell(emps,"active",false,9)>
<cfset querysetcell(emps,"firstname","Sean",10)>
<cfset querysetcell(emps,"department","CF",10)>
<cfset querysetcell(emps,"salary","250000",10)>
<cfset querysetcell(emps,"active","No",10)>
<cfform name="form01">
<cfgrid format="html" insert="yes" insertButton="Add Row"
name="grid01"
selectmode="edit"
width=600
collapsible="true"
title="Employees"
autowidth="yes"
query="emps"
sort="yes"
groupField="active">
<cfgridcolumn name="FirstName" header="FirstName"/>
<cfgridcolumn name="Department" header="Department" />
<cfgridcolumn name="Salary" display=true header="Salary" type="numeric"
values="1000000,1200000" valuesdisplay="1000000,1200000"/>
<cfgridcolumn name="Active" display=true header="Contract" type="boolean" />
</cfgrid>
</cfform>
833
For details of various types of masks that can be used, see the CFML Reference Guide.
Datehandling when the attribute mask is used in ColdFusion 9.0.1
If the attribute mask is applied to a datefield column in an HTML grid, ColdFusion converts the date to an intermediate
format as shown here:
MMMMM, dd yyyy HH:mms
for example,
January, 19 2005 07:35:42
This is required for proper date conversion and is applicable both when data is sent to the server (for example, when
using an onChange grid event) and when data is received from the server (for example, populating a date field in a
grid). Therefore, in some cases, users might have to format the date if they are updating a date column in the database.
Note: Date values which are NULL are sent as empty strings when the form is submitted. In such cases, set the value to
NULL explicitly while updating the date column in the database.
834
If you use a bind expression, the cftree tag can have only a single cftreeitem tag. Therefore, the function or URL
called by the bind expression must be able to populate all levels of the tree.
When a tree item expands, the CFC or JavaScript function or active page specified by the bind attribute returns an
array with the values for the child nodes of the item. The dynamic tree code on the client constructs the child items
by using these values.
When a control to which the tree is bound generates an event that the tree is listening for, the tree is refreshed. For
example, if the tree uses a bind expression that includes a select box as a bind parameter, the tree collapses to the
root nodes when the selected value in the select box changes.
When you use a bind expression to populate a cftree control, specify a CFC function, JavaScript function, or URL,
and pass the following bind parameters. If you omit either of the parameters from your function call or URL, you get
an error. These parameters provide information about the tree and its state, and are automatically provided by the
control.
Bind parameter
Description
{cftreeitempath}
Passes the path of the current (parent) node to the method, which uses it to generate the next node.
{cftreeitemvalue}
Passes the current tree item value (normally the value attribute)
The called function or URL cannot return nested arrays and structures, that is, it can only return a single level of items.
When a function or URL is first called to populate the root-level tree items, the value passed in the cftreeitemvalue
variable is the empty string. Your bind function can test for an empty string to determine that it is populating the root
level of the tree.
The @none event specifier is also useful if you use the ColdFusion.Tree.refresh JavaScript function to manually refresh
the tree. When you call the Refresh function, the bind expression fetches data from all bind parameters, including
@none parameters. If you specify @none in all bind parameters that specify other controls, the tree does not respond
automatically to changes in the other controls, but it does pick up data from the bind parameters when you use the
ColdFusion.Tree.Referesh function to explicitly refresh the tree.
The format of the data that the function or URL in a bind expression must return depends on the type of bind
expression
835
Bind type
Return value
CFC
A ColdFusion array of structures. ColdFusion automatically converts the structure to JSON format when it
returns the result to the caller. Alternatively, you can return a JSON representation of the structure.
JavaScript
URL
Each structure in the array of structures or objects defines the contents and appearance of the node for a child item.
Each structure must have a VALUE field, and can have the following fields. Except for LEAFNODE, these structure
keys correspond to cftreeitem attributes.
DISPLAY
EXPAND
HREF
IMG
IMGOPEN
LEAFNODE
TARGET
Note: If a CFC does not return a value field, you do not get an error, but the tree does not work properly.
The LEAFNODE structure element is only used in the bind response structures. It must be a Boolean value that
identifies whether the node is a leaf. If the value is true, the tree does not show a +/- expansion indicator in front of
the node, and users cannot expand the node.
If your bind expression specifies a JavaScript function, the function must use all-uppercase letters for the field names;
for example, use VALUE and DISPLAY, not value and display. ColdFusion uses all capital letters in the structure key
names. ColdFusion is not case-sensitive, so CFCs can use lowercase letters for the field names; JavaScript is casesensitive, so the JavaScript function must match the uppercase field names.
If you use a URL to get the tree items from a CFML page, you can use the serializeJSON function to convert the array
to JSON format. If the array with the tree items is named itemsArray, for example, the following line specifies the page
output:
<cfoutput>#serializeJSON(itemsArray)#</cfoutput>
The following example shows the maketree.cfc file with the getNodes method that is called when the user expands a node:
836
<cfcomponent>
<cffunction name="getNodes" returnType="array" output="no" access="remote">
<cfargument name="nodeitemid" required="true">
<cfargument name="nodeitempath" required="true">
<!--- The initial value of the top level is the empty string. --->
<cfif nodeitemid IS "">
<cfset nodeitemid =0>
</cfif>
<!--- Create an array with one element defining the child node. --->
<cfset nodeArray = ArrayNew(1)>
<cfset element1 = StructNew()>
<cfset element1.value = nodeitemid + 1>
<cfset element1.display = "Node #nodeitemid#">
<cfset nodeArray[1] = element1>
<cfreturn nodeArray>
</cffunction>
</cfcomponent>
837
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!--- The loadimage function displays the image of the selected art.
It is called when the user clicks the image item. --->
<script>
function loadImage(img) {
var imgURL = '<img src="/cfdocs/images/artgallery/'+img+'">';
var imgDiv = document.getElementById('image');
imgDiv.innerHTML = imgURL;
}
</script>
</head>
<body>
<!--- The form uses a table to place the tree and the image. --->
<cfform name="ex1" action="ex1.cfm" method="post">
<table>
<tr valign="top">
<td>
<cftree name="mytree" format="html">
<!--- When you use a bind expression, you must have only one
cftreeitem, which populates the tree level. --->
<cftreeitem bind="cfc:tree.getItems({cftreeitempath},
{cftreeitemvalue})">
</cftree>
</td>
<td>
<div id="image"></div>
</td>
</tr>
</table>
</cfform>
</body>
</html>
838
<cfcomponent output="false">
<cfset variables.dsn = "cfartgallery">
<!--- Function to populate the current level of the tree. --->
<cffunction name="getItems" returnType="array" output="false" access="remote">
<cfargument name="path" type="string" required="false" default="">
<cfargument name="value" type="string" required="false" default="">
<cfset var result = arrayNew(1)>
<cfset var q = "">
<cfset var s = "">
<!--- The cfif statements determine the tree level. --->
<!--- If there is no value argument, the tree is empty. Get the media types. --->
<cfif arguments.value is "">
<cfquery name="q" datasource="#variables.dsn#">
SELECT mediaid, mediatype
FROM media
</cfquery>
<cfloop query="q">
<cfset s = structNew()>
<cfset s.value = mediaid>
<cfset s.display = mediatype>
<cfset arrayAppend(result, s)>
</cfloop>
<!--- If the value argument has one list entry, it is a media type. Get the artists for
the media type.--->
<cfelseif listLen(arguments.value) is 1>
<cfquery name="q" datasource="#variables.dsn#">
SELECT artists.lastname, artists.firstname, artists.artistid
FROM art, artists
WHERE art.mediaid = <cfqueryparam cfsqltype="cf_sql_integer"
value="#arguments.value#">
AND art.artistid = artists.artistid
GROUP BY artists.artistid, artists.lastname, artists.firstname
</cfquery>
<cfloop query="q">
<cfset s = structNew()>
<cfset s.value = arguments.value & "," & artistid>
<cfset s.display = firstName & " " & lastname>
<cfset arrayAppend(result, s)>
</cfloop>
<!--- We only get here when populating an artist's works. --->
<cfelse>
<cfquery name="q" datasource="#variables.dsn#">
SELECT art.artid, art.artname, art.price, art.description,
art.largeimage, artists.lastname, artists.firstname
FROM art, artists
WHERE art.mediaid = <cfqueryparam cfsqltype="cf_sql_integer"
value="#listFirst(arguments.value)#">
AND art.artistid = artists.artistid
AND artists.artistid = <cfqueryparam cfsqltype="cf_sql_integer"
839
value="#listLast(arguments.value)#">
</cfquery>
<cfloop query="q">
<cfset s = structNew()>
<cfset s.value = arguments.value & "," & artid>
<cfset s.display = artname & " (" & dollarFormat(price) & ")">
<cfset s.href = "javaScript:loadImage('#largeimage#');">
<cfset s.children=arrayNew(1)>
<!--- leafnode=true prevents node expansion and further calls to the
bind expression. --->
<cfset s.leafnode=true>
<cfset arrayAppend(result, s)>
</cfloop>
</cfif>
<cfreturn result>
</cffunction>
</cfcomponent>
Description
ColdFusion.Tree.getTreeObject
Gets the underlying Yahoo User Interface Library TreeView JavaScript object.
ColdFusion.Tree.refresh
For more information, see the ColdFusion.Tree.getTreeObject and ColdFusion.Tree.refresh functions in the CFML
Reference.
840
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<!--- Display the text if the form has been submitted with text. --->
<cfif isdefined("form.text01") AND (form.text01 NEQ "")>
<cfoutput>#form.text01#</cfoutput><br />
</cfif>
<!--- A form with a basic rich text editor and a submit button. --->
<cfform name="form01" >
<cftextarea richtext=true name="text01" />
<cfinput type="submit" value="Enter" name="submit01"/>
</cfform>
</body>
</html>
Note: If you use the rich text editor in your pages, you cannot configure your web server to have ColdFusion process files
with the .html or .htm extensions. The default HTML processor must handle pages with these extensions.
Configuring the rich text editor
You can customize the rich text editor in many ways. The cftextarea attributes support some basic customization
techniques. For more detailed information, see the FCKEditor website at http://wiki.fckeditor.net/.
Defining custom toolbars
You can use the following techniques to control the appearance of the toolbar:
This configuration defines a toolbar with two rows that contain a subset of the full tool set designed to support basic
text editing.
841
The name attribute specifies the name that appears in the Style selector.
The element attribute specifies the HTML element that surrounds the text.
Each Attribute child element defines the name and value of an attribute of the HTML tag.
For example, the following definition creates a style that makes the selected text bold and underlined:
<Style name="Custom Bold And Underline " element="span">
<Attribute name="style" value="font-weight: bold; text-decoration: underline;"/>
</Style>
If you use a custom XML file, instead of fckstyles.xml, to define your styles, specify the filepath in the stylesXML
attribute.
Defining custom templates
The editor includes a set of basic templates that insert HTML formatting into the textarea control. For example, the
ImageandTitle template places a placeholder for an image on the left of the area, and a title and text to the right of
the image. Then right-click the image area to specify the image source and other properties, and replace the
placeholder title and text.
You create your own templates by creating entries in cf_webRoot/CFIDE/scripts/ajax/FCKEditor/fcktemplates.xml
file. Each template XML entry has the following format:
<Template title="template title" image="template image">
<Description>template description</Description>
<Html>
<![CDATA[
HTML to insert in the text area when the user selects the template.
]]>
</Html>
</Template>
The template title, image, and description appear in the Templates dialog box that appears when the user clicks the
template icon on the rich text editor toolbar.
842
The name "Title and Text" and the template1.gif image appear in the template selection dialog box.
If you use a custom XML file, instead of fcktemplates.xml, to define your templates, specify the file path in the
templatesXML attribute.
Defining custom skins
To create a custom skin that you specify in the skin attribute, create a subdirectory of the
cf_webRoot/CFIDE/scripts/ajax/FCKeditor/editor/skins directory. The name of this subdirectory is the name that you
use to specify the skin in the skin attribute. The custom skin directory must contain an images subdirectory and have
the following files:
fck_editor.css: Defines the main interface, including the toolbar, its items (like, buttons, panels) and the context menu.
fck_dialog.css: Defines the basic structure of dialog boxes (standard for all dialogs).
fck_strip.gif: Defines the Default toolbar buttons and context menu icons. It is a vertical image that contains all
icons placed one above the other. Each icon must correspond to a 16x16 pixels image. You can add custom images
to this strip.
images/toolbar.buttonarrow.gif: Defines the small arrow image used in the toolbar combos and panel buttons.
Place all other images used by the skin (that are specified in the CSS files) in the images subfolder.
The most common way of customizing the skin is to change the fck_editor.css and fck_dialog.css files. For information
on the skin format and contents, see the comments in those files.
To correctly display label text next to the control in both Internet Explorer and Firefox, surround the label text in
a <div style="float:left;"> tag and place three <br> tags between each line.
Consider specifying an overflow attribute with a value of visible in the cflayoutarea tag so that if the pop-up
calendar exceeds the layout area boundaries, it appears completely.
If you use a mask attribute to control the date format, it does not prevent the user from entering dates that do not
conform to the mask. The mask attribute determines the format for dates that users select in the pop-up calendar.
Also, if the user types a date in the field and opens the pop-up calendar, the calendar displays the selected date only
if the entered text follows the mask pattern. If you do not specify a mask attribute, the pop-up only matches the
default matching pattern.
If the user types a date with a month name or abbreviation in the control, instead of picking a date from the
calendar, the selected date appears in the pop-up calendar only if both of the following conditions are true:
The month position and name format match the mask pattern.
843
The month name matches, case correct, the month names specified by the monthNames attribute, or, for an mmm
mask, their three-letter abbreviations.
If the date mask specifies yy for the years, the pop-up calendar uses dates in the range 1951-2050, so if the user
enters 3/3/49 in the text field, the calendar displays March 3, 2049.
If the user enters invalid numbers in a date, the pop-up calendar calculates a valid date that corresponds to the
invalid input. For example, if the user enters 32/13/2007 for a calendar with a dd/mm/yyyy mask, the pop-up
calendar displays 01/02/2008.
The following example shows a simple tabbed layout where each tab contains a form with several datefield controls.:
<html>
<head>
</head>
<body>
<cflayout type="tab" tabheight="250px" style="width:400px;">
<cflayoutarea title="test" overflow="visible">
<br>
<cfform name="mycfform1">
<div style="float:left;">Date 1: </div>
<cfinput type="datefield" name="mydate1"><br><br><br>
<div style="float:left;">Date 2: </div>
<cfinput type="datefield" name="mydate2" value="15/1/2007"><br><br><br>
<div style="float:left;">Date 3: </div>
<cfinput type="datefield" name="mydate3" required="yes"><br><br><br>
<div style="float:left;">Date 4: </div>
<cfinput type="datefield" name="mydate4" required="no"><br><br><br>
</cfform>
</cflayoutarea>
<cflayoutarea title="Mask" overflow="visible">
<cfform name="mycfform2">
<br>
<div style="float:left;">Date 1: </div>
<cfinput type="datefield" name="mydate5" mask="dd/mm/yyyy">
(dd/mm/yyyy)<br><br><br>
<div style="float:left;">Date 2: </div>
<cfinput type="datefield" name="mydate6" mask="mm/dd/yyyy">
(mm/dd/yyyy)<br><br><br>
<div style="float:left;">Date 3: </div>
<cfinput type="datefield" name="mydate7" mask="d/m/yy">
(d/m/yy)<br><br><br>
<div style="float:left;">Date 4: </div>
<cfinput type="datefield" name="mydate8" mask="m/d/yy">
(m/d/yy)<br><br><br>
</cfform>
</cflayoutarea>
</cflayout>
</body>
</html>
Note: In Internet Explorer versions previous to IE 7, this example shows the calendars for the first three fields in a page
behind the following input controls.
844
The control suggests entries from a static list of values. To use a static suggestion list, specify the list entries in the
autosuggest attribute, and separate the entries by the character specified by the delimiter attribute (by default, a
comma), as the following example shows:
<cfinput type="text"
autosuggest="Alabama\Alaska\Arkansas\Arizona\Maryland\Minnesota\Missouri"
name="city" delimiter="\">
In this example, if you type the character a (in uppercase or lowercase) in the cfinput control, the list of states that
start with A appears in a drop-down list. You navigate to a selection by using the arrow keys, and press Enter to select
the item.
You also have the control suggest values from a dynamically generated suggestion list. To use a dynamic list, specify a
CFC function, JavaScript function, or URL in the autosuggest attribute. Use the autosuggestBindDelay attribute
to specify the minimum time between function invocations as the user types. This limits the number of requests that
are sent to the server. If you use a dynamic list, the input field has an icon to its right that animates while suggestions
are fetched.
When you use a bind expression you must include a {cfautosuggestvalue} bind parameter in the function call or
URL parameters. This parameter binds to the user input in the input control and passes it to the function or page.
A CFC or JavaScript autosuggest function must return the suggestion values as a one-dimensional array or as a
comma-delimited list.
The HTTP response body from a URL must consist only of the array or list of suggestion values in JSON format. In
ColdFusion, you can use the serializeJSON function to convert an array to JSON format. If an array with the
suggestions is named nodeArray, for example, the following line would specify the only output on a CFML page that
is called by using a bind expression with a URL:
<cfoutput>#serializeJSON(nodeArray)#</cfoutput>
You do not have to limit the returned data to values that match the cfautosuggestvalue contents, because the clientside code displays only the values that match the user input. In fact, the called function or page does not even have to
use the value of the cfautosuggestvalue parameter that you pass to it. However, use the parameter if the returned
data would otherwise be long.
The following example shows how to use a bind expression to populate autosuggest lists. The Last Name text box
displays an autosuggest list with all last names in the database that match the keys typed in the box. The First Name
text box uses binding to the Last Name text box to display only the first names that correspond to the last name and
the text entered in the box. The database query limits the responses to only include results that match the autosuggest
criteria, so the autosuggest list displays all the returned results, and the suggestions only match if the database entry
has a case-correct match.
845
To test this example with the cfdocexamples database, type S in the first box and the autosuggest list shows Smith and
Stewart. If you select Smith and enter A or J in the First Name box, you get a name suggestion.
The following example shows the application:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<cfform>
Last Name:<br />
<cfinput type="text" name="lastName"
autosuggest="cfc:suggestcfc.getLNames({cfautosuggestvalue})"><br />
<br />
First Name:<br />
<cfinput type="text" name="firstName"
autosuggest="cfc:suggestcfc.getFNames({cfautosuggestvalue},{lastName})">
</cfform>
</body>
</html>
846
<cfcomponent>
<cffunction name="getLNames" access="remote" returntype="array" output="false">
<cfargument name="suggestvalue" required="true">
<!--- The function must return suggestions as an array. --->
<cfset var myarray = ArrayNew(1)>
<!--- Get all unique last names that match the typed characters. --->
<cfquery name="getDBNames" datasource="cfdocexamples">
SELECT DISTINCT LASTNAME FROM Employees
WHERE LASTNAME LIKE <cfqueryparam value="#suggestvalue#%"
cfsqltype="cf_sql_varchar">
</cfquery>
<!--- Convert the query to an array. --->
<cfloop query="getDBNames">
<cfset arrayAppend(myarray, lastname)>
</cfloop>
<cfreturn myarray>
</cffunction>
<cffunction name="getFNames" access="remote" returntype="array"
output="false">
<cfargument name="suggestvalue" required="true">
<cfargument name="lastName" required="true">
<cfset var myarray = ArrayNew(1)>
<cfquery name="getFirstNames" datasource="cfdocexamples">
<!--- Get the first names that match the last name and the typed characters. --->
SELECT FIRSTNAME FROM Employees
WHERE LASTNAME = <cfqueryparam value="#lastName#"
cfsqltype="cf_sql_varchar">
AND FIRSTNAME LIKE <cfqueryparam value="#suggestvalue & '%'#"
cfsqltype="cf_sql_varchar">
</cfquery>
<cfloop query="getFirstNames">
<cfset arrayAppend(myarray, Firstname)>
</cfloop>
<cfreturn myarray>
</cffunction>
</cfcomponent>
847
In HTML forms, you can specify maximum, minimum, and increment values, to help you quickly filter complex
results. The available slider controls are: Vertical, with controls that can be adjusted to the top or bottom; Horizontal,
with controls that can be adjusted to the left or right; Tip, that displays the values as data tips; and Snapping, that moves
in incremental values.
Manipulating slider at runtime
The following code illustrates how you can manipulate a slider at runtime:
<script language="javascript">
//use Coldfusion AJAX functions
var sliderChange = function(slider,value)
{
//get slider name
slidername = slider.getId();
//get slider value
currValue = ColdFusion.Slider.getValue(slidername);
//set a new slider value
newValue = parseInt(currValue+10);
ColdFusion.Slider.setValue(slidername,newValue);
//hide slider
if(confirm("Do you want to hide slider?"))
{
ColdFusion.Slider.hide(slidername);
}
//show slider
if(confirm("Do you want to show slider?"))
{
ColdFusion.Slider.show(slidername);
}
//disable slider
if(confirm("Do you disable the slider?"))
{
ColdFusion.Slider.disable(slidername);
}
//enable slider
if(confirm("Do you enable the slider?"))
{
ColdFusion.Slider.enable(slidername);
}
}
var sliderDrag = function(slider)
{
//get slider name
slidername = slider.getId();
document.getElementById('currentSliderValue').innerHTML = "Current Slider value :
<font color='red'><strong>" + ColdFusion.Slider.getValue(slidername) + "<strong></font>";
}
</script>
<br>
<cfform name="frm1">
848
<p>
<span id="currentSliderValue">Current Slider Value: <font
color="red"><strong>50</strong></font></span><br>
</p>
</cfform>
<p>
<br><b>Volume</b>:
<cfslider
name="s"
format="html"
min=1
max=100
value="50"
tip="yes"
onChange="sliderChange"
onDrag = "sliderDrag"
vertical="no"
width="200pt"
>
</p>
earth
terrain
satellite
hybrid
map (default)
849
<br>
<cfoutput>
<table>
<tr>
<td bgcolor='red'><h4><font color='white'>URL Bind Example</font></td>
</tr>
</table>
Map Name: #cfmapname#<br>
Latitude, Longitude: (#DecimalFormat(cfmaplatitude)#,#DecimalFormat(cfmaplongitude)#)<br>
Address: #cfmapaddress#<br>
</cfoutput>
Description
cfmapname
cfmaplatitude
The latitude value for the location, in degrees. This value is set as the center of the map.
cfmaplongitude
The longitude value for the location, in degrees. This value is set as the center of the map.
cfmapaddress
The address of the location, which is set as the center of the map.
The format of the returned data depends on how you get the data:
Bind type
Return value
CFC
A ColdFusion structure. ColdFusion automatically converts the structure for return to the caller.
Alternatively, you can return a JSON representation of the structure.
URL
JavaScript
A JavaScript object.
850
<cfcomponent>
<cffunction name="getMapData" access="remote">
<cfargument name="cfmapname">
<cfargument name="cfmaplatitude">
<cfargument name="cfmaplongitude">
<cfargument name="cfmapaddress">
<cfsavecontent variable="markup">
<br>
<cfoutput>
<table>
<tr>
<td bgcolor='red'><h4><font color='white'>CFC Bind Example</font></td>
</tr>
</table>
Map Name: #cfmapname#<br>
Latitude, Longitude:
(#DecimalFormat(cfmaplatitude)#,#DecimalFormat(cfmaplongitude)#)<br>
Address: #cfmapaddress#<br>
</cfoutput>
</cfsavecontent>
<cfreturn markup>
</cffunction>
</cfcomponent>
The following example shows how to populate dynamic data using a JavaScript bind expression:
<script language="JavaScript">
var getMapData = function(cfmapname, cfmaplatitude, cfmaplongitude, cfmapaddress){
var msg = "";
msg = msg + "Map Name: " + cfmapname + "<br>";
msg = msg + "Latitude,longitude: " + "(" + cfmaplatitude + "," + cfmaplongitude + ")"
+ "<br>";
msg = msg + "Address: " + cfmapaddress + "<br>";
//alert(msg);
return "<br><table><tr><td bgcolor='red'><h4><font color='white'>" + "Javascript Bind
Example" + "</font></td></tr></table><hr>" + msg;
}
</script>
<cfmap
centeraddress="Hobart, Tasmania, Australia"
name="map1"
type="map"
tip="Hobart, Tasmania, Australia"
zoomControl="small3d"
markerbind="javascript:getMapData({cfmapname}, {cfmaplatitude}, {cfmaplongitude},
{cfmapaddress})"
showmarkerwindow = true>
<cfmapitem name="m1" address="Taj Mahal, Agra, India" tip="Taj Mahal, Agra, India">
<cfmapitem name="m2" latitude="40.46" longitude="117.05" showmarkerwindow=true tip="Great
Wall of China, Bejing">
<cfmapitem name="m3" address="Stonehenge, England" tip="Stonehenge, England"
showmarkerwindow = false>
</cfmap>
The following example shows how to populate dynamic data using a URL bind expression:
851
<cfmap
centeraddress="Hobart, Tasmania, Australia"
name="map1"
type="map"
tip="Hobart, Tasmania, Australia"
zoomControl="small3d"
markerbind="url:mapdata.cfm?cfmapname={cfmapname}&cfmaplatitude={cfmaplatitude}&cfmaplongitu
de={cfmaplongitude}&cfmapaddress={cfmapaddress}"
showmarkerwindow = true>
<cfmapitem name="m1" address="Taj Mahal, Agra, India" tip="Taj Mahal, Agra, India">
<cfmapitem name="m2" latitude="40.46" longitude="117.05" showmarkerwindow=true tip="Great
Wall of China, Bejing">
<cfmapitem name="m3" address="Stonehenge, England" tip="Stonehenge, England"
showmarkerwindow = false>
</cfmap>
Using the cfajaximport tag. You specify the map API key in the params attribute as follows:
<cfajaximport params="#{googlemapkey='Map API Key'}#"
Using the Settings page in the ColdFusion Administrator. Specify the map API key in the Google Map Key field.
You can also specify the map API key in runtime.cfc.
Styling markers
You can specify the following:
Custom marker icon: Specify the path to the icon using the markericon attribute. Ensure that you specify an image
of appropriate size.
Marker icon color: Use the markercolor attribute. You can specify a color of your preference only for the default
icon and not for others.
Automatically runs the progress bar for a duration that you specify.
Dynamically loads data using bind expressions
Lets styling of the progress bar
852
Uses callback and error handlers that give control to the users after the progress bar completes processing or if it
encounters any exceptions.
The following pb.cfc has the function that returns data for the progressbar:
853
<cfcomponent>
<cffunction name="resetStatus" access="remote">
<!--Clear count from session so that next time the progress bar runs from the start
time.
--->
<cfif session.count gte 10>
<cfset structdelete(session,"count")>
</cfif>
</cffunction>
<cffunction name="getProgessData" access="remote">
<!--- use a count to track progress --->
<cfif not isdefined('session.count')>
<cfset session.count = 1>
<cfelse>
<cfset session.count = session.count + 1 >
</cfif>
<!--- struct with status and message components of the progressbar --->
<cfset data = {status=session.count * 0.1,message=(session.count * 10) & "%"}>
<cfreturn data>
</cffunction>
</cfcomponent>
The following CFM code explains how to use the URL bind expression:
<head>
<script>
var init = function()
{
document.getElementById('cfpbLabel').style.display = 'block';
ColdFusion.ProgressBar.show('pBar');
ColdFusion.ProgressBar.start('pBar');
}
var hideProgessBar = function()
{
document.getElementById('cfpbLabel').style.display = 'none';
ColdFusion.ProgressBar.hide('pBar');
}
</script>
</head>
<cfform>
<div id="cfpbLabel" style="display:none">
Saving File:
</div>
<cfprogressbar
name="pBar"
autodisplay=false
bind="url:progressdata.cfm"
onComplete="hideProgessBar"
width="400">
<cfset ajaxOnLoad('init')>
</cfform>
854
855
Manual mode
In the manual mode, you specify the duration the progress bar takes to complete the display of progress.
In the following example, autodisplay is set to false as a result of which the progress bar is not shown when the
page is first loaded. When the page is loaded, init function is invoked and the function displays and runs the progress
bar. The default interval used in this mode is one second.
<head>
<script>
var init = function()
{
document.getElementById('cfpbLabel').style.display = 'block';
ColdFusion.ProgressBar.show('pBar');
ColdFusion.ProgressBar.start('pBar');
}
var hideProgessBar = function(){
document.getElementById('cfpbLabel').style.display = 'none';
ColdFusion.ProgressBar.hide('pBar');
}
</script>
</head>
<cfform>
<div id="cfpbLabel" style="display:none">
Saving File:
</div>
<cfprogressbar
name="pBar"
duration="10000"
autodisplay=false
onComplete="hideProgessBar"
width="400"
/>
<cfset ajaxOnLoad('init')>
</cfform>
856
The sleep function in the following CFC provides sleep functionality in the JavaScript code:
<cfcomponent>
<cffunction name="sleep" access="remote">
<cfargument name="timetosleep" default="1000">
<cfset sleep(timetosleep)>
</cffunction>
</cfcomponent>
857
858
<cfmessagebox
type="alert"
name="msgbox1"
title="Download Status"
message="File Download Complete"
icon="info"
width="400"
bodyStyle="background-color:white;color:blue"
x=300
y=200>
<br><br>
<input
type="button"
name="alert"
onClick="javascript:ColdFusion.MessageBox.show('msgbox1');"
value="Alert MessageBox"
>
859
ColdFusion supports data binding in many tags. Binding allows an application that uses form and display tags, such
as cfselect and cfwindow, to dynamically display information based on form input. In the simplest application,
you display form data directly in other form fields, but usually you pass form field data as parameters to CFC or
JavaScript functions or URLs and use the results to control the display. Data binding uses events to automatically
update the display, typically when the bound input data changes. You can also use the
ColdFusion.Ajax.submitForm JavaScript function to get the current value of any bindable element.
The cfajaxproxy tag creates a JavaScript proxy that represents a CFC on the server. It manages the
communication between the client and server, and provides several functions to simplify and manage handling the
communication and its results. This tag provides access to all remote functions in a CFC. It also lets applications,
including applications that use Ajax frameworks or widget sets such as Dojo or Backbase, easily access data from
ColdFusion servers.
The cfsprydataset tag lets you use bind expressions to dynamically create and update Adobe Spry data sets.
Applications that use Spry framework elements, such as dynamic regions, use this tag to populate the Spry elements
with information based on ColdFusion control input. This feature lets you easily intermix Spry and ColdFusion
controls.
The cfajaximport tag specifies the location of the JavaScript and CSS files that a ColdFusion page imports. You
also use this tag to selectively import files required by specific Ajax-based tags and functions. The ability to change
the file location lets you support a wide range of configurations and use advanced techniques, such as applicationspecific styles. Although ColdFusion automatically determines and imports the required files, sometimes you must
manually specify the information.
ColdFusion provides several CFML functions that let you create and consume JSON format data on the server and
let you prepare data for use in HTML cfgrid tags.
You display a floating logging window that shows client-side logging and debugging information. ColdFusion Ajax
features display information and error messages in this window, and several logging tags let you display additional
information, including the structure of complex JavaScript variables.
User interface features
Ajax-based HTML controls including the following:
Tree
Grid
Rich text editor
Date field
Autosuggest text input
Pop-up menus and menu bars.
Container tags that provide bordered, box, and tabbed layouts, pop-up windows, and pod regions.
A cfdiv container tag that enables asynchronous form submission and binding in HTML div and other regions.
Tool tips for specific controls and HTML regions.
For detailed information on using the user interface features, see Using Ajax User Interface Components and
Features on page 804.
860
UI tags
UI tags
Functions
cfajaximport
cfdiv
cfselect
AjaxLink
cfajaxproxy
cfgrid
cftextarea
AjaxOnLoad
cfsprydataset
cfinput
cftree
DeserializeJSON
cflayout
cftooltip
IsJSON
cfmenu
cfwindow
QueryConvertForGrid
cfpod
SerializeJSON
ColdFusion form control attributes and values. You can bind to the following controls:
cfgrid
cfinput with checkbox, datefield, file, hidden, radio, or text types
cfselect
cftextarea
cftree
Spry data set elements
Note: You cannot use a bind expression to bind to controls in a dynamically loaded region. For example, you cannot bind
from a control on one page to a control in a layout area on that page if the cflayoutarea tag uses a source attribute
for its contents. However, a dynamically loaded region binds to controls on the page that loads it, so the file specified by
the source attribute uses bind expressions that specify controls on the page that contains the cflayoutarea tag.
The results of the bind expression determine the value of the tag that uses the expression. For example, if you specify
a URL in a bind expression as the source attribute of a cfwindow control, the page specified by the URL must return
the full contents of the window.
For more examples, see Using Ajax User Interface Components and Features on page 804 and the reference pages
for controls that support binding.
861
cfc:componentPath.functionName(parameters)
Note: In ColdFusion 9, the component path cannot use a mapping. The componentPath value must be a dotdelimited path from the web root or the directory that contains the current page.
javascript:functionName(parameters)
url:URL?parameters
URL?parameters
A string containing one or more instances of {bind parameter}, such as {firstname}.{lastname}@{domain}
In formats 1-4 the parameters normally include one or more bind parameters. The following table lists the tag
attributes that support bind expressions and the formats each use:
Attribute
Tags
Supported formats
autosuggest
cfinput type="text"
1, 2, 3
bind
1, 2, 3, 5
bind
1, 2, 3
onChange
cfgrid
1, 2, 3
source
In these examples, {book} and {inputForm:city} specify bind parameters that dynamically get data from the book
and city controls, and the city control is in the inputForm form.
If a bind attribute specifies a page that defines JavaScript functions, the function definitions on that page must have
the following format:
functionName = function(arguments) {function body}
Function definitions that use the following format may not work:
function functionName (arguments) {function body}
However, Adobe recommends that you include all custom JavaScript in external JavaScript files and import them on
the applications main page, and not write them inline in code that you get using the source attribute. Imported pages
do not have this function definition format restriction.
Specifying bind parameters
A bind parameter specifies a form control value or other attribute, as in the following example:
bind="cfc:myapplication.bookSearch.getStores({form1:bookTitle})"
In this example, the bind parameter is form1:bookTitle and specifies the value attribute of the bookTitle field of the
form1 form.
Bind parameters have either of the following formats:
862
{[formName:]controlName[.attributeName][@event]}
{SpryDataSetName.fieldName}
The brackets ([]) indicate optional contents and are not part of the parameter.
Note: To include a literal brace character in a bind expression, escape the character with a backslash, as \{, \}.
The formname value
The formname entry identifies the form that contains the control you are binding to. Specify a form name if multiple
forms contain bind targets with the same names. To specify the form name, start the bind expression with the forms
id attribute the name attribute if you did not specify an id attribute, and follow it with a colon (:). To specify the book
control that is in a form named inputForm, for example, use the following format:
bind="cfc:myapp.bookorder.getChoices({inputForm:book})"
863
Note: You can bind to the display text of a select box, instead of the value, by specifying an attribute name of innerHTML.
Note: When you bind to a check box, use the @click event specifier to ensure that the bind expression is triggered in
Internet Explorer when the user selects or deselects the check box, not when the box loses focus.
Grids and trees do not have default bind attributes.
Always specify a grid target attribute by using the format {gridID.columnName}. The bind expression gets the value
of the specified column in the selected row.
For trees, you must bind to a specific node in the tree. Specify the node by using the node ID or an explicit path to
the node.
To bind to a Spry data set element or attribute, use standard Spry path notation. For example, specify an element name.
The event value
By default, the bind expression function executes each time the control specified in the bind parameter has an
onChange event. To trigger updates on a different JavaScript event, end the bind expression with an at sign (@) and
the event name, without the on prefix. The following code, for example, executes the getChoices CFC each time the
user presses the mouse button while the pointer is over the book control:
bind="cfc:myapp.bookorder.getChoices({inputForm:book@mousedown})"
Note: To bind to a cfinput control with type attribute of button, specify a bind event setting, such as click. The
change event is the default event has no effect.
When you bind to a Spry data set, do not specify an event. The expression is evaluated when the selected row changes
in the data set, or when the data set reloads with new data.
You can also specify that a specific bind parameter never triggers bind expression reevaluation, by specifying @none as
the event. This is useful, for example, if a bind expression uses multiple bind parameters binding to different form
fields, and you want the bind expression to trigger changes only when one of the fields changes, not when the others
change. In this case, you would specify @none for the remaining fields, so events from those fields would not trigger
the bind. The following code shows this use:
bind="cfc:books.getinfo({iForm:book}, {iForm:author@none})"
The @none event specifier is also useful when used with autosuggest text inputs, trees and grids, as follows:
When you use an autosuggest text input, the bind expression is evaluated as a user types in text, and picks up data
from all bind parameters, including those parameters with @none specified. Therefore, for autosuggest, specify
@none for all bind parameters, because there is no way for it to react to changes in the parameters.
When you call the ColdFusion.Grid.refresh or ColdFusion.Tree.refresh function, the function fetches data
from all bind parameters when it evaluates the bind expression, including any parameters with @none specified. If
you specify @none for all bind parameters, the tree or grid might not respond to changes in other controls, but gets
data from all the bind parameters each time you explicitly refresh it.
Using CFC functions in bind expressions
As with JavaScript functions, you pass arguments to a CFC function specified in a bind expression positionally. When
you do this, the argument names in a CFC function definition do not have to be the same as the bind parameter names,
but the arguments in the bind expression must be in the same order as the arguments in the CFC function definition.
Alternatively, you pass named CFC function arguments. Then, the bind expression and CFC function must use the
same names for the arguments, and the function does not have to define the arguments in the same order as they are
passed. To specify argument names in a bind expression, use a format such as the following, which uses two named
parameters, arg1 and arg2:
864
bind="cfc:mycfc.myfunction(arg1={myform:myfield1},arg2={myform:myfield2})"
Test.cfm
<cfajaxproxy cfc="mycfc.utils" jsclassname='jsobjname' />
Example
In this example, a per-app mapping named mycfcs has been created in Application.cfc pointing to "c:\components".
For the sample code to work, create a folder named components in your system root (in this example, c:\) and copy
the Employee.cfc to that folder.
Application.cfc
<cfcomponent>
<cfset this.name = "cfcoutsidewebroot">
<cfset this.sessionmanagement = true>
<Cfset mappingname = "/mycfcs">
<Cfset mappingpath = "c:\components\">
<cfset this.mappings[mappingname] = mappingpath>
</cfcomponent>
Employee.cfc
865
<cfcomponent>
<cfscript>
remote any function
getEmployees(page,pageSize,gridsortcolumn="EMP_ID",gridsortdirection="ASC"){
var startRow = (page-1)*pageSize;
var endRow = page*pageSize;
if(!isdefined("arguments.gridsortcolumn") or
isdefined("arguments.gridsortcolumn") and trim(arguments.gridsortcolumn) eq "")
gridsortcolumn = "EMP_ID";
if(!isdefined("arguments.gridsortdirection") or
isdefined("arguments.gridsortdirection") and arguments.gridsortdirection eq "")
gridsortdirection = "ASC";
var mysql = "SELECT Emp_ID, FirstName, EMail, Department FROM Employees";
if(isdefined("arguments.gridsortcolumn") and arguments.gridsortcolumn neq "")
mysql = mysql & " ORDER BY " & gridsortcolumn;
if(isdefined("arguments.gridsortdirection") and arguments.gridsortdirection neq
"")
mysql = mysql & " " & gridsortdirection ;
rs1 = new query(name="team", datasource="cfdocexamples", sql=mysql).execute();
return QueryConvertForGrid(rs1.getResult(), page, pageSize);
}
Employee.cfm
<cfform>
<cfgrid
format="html"
name="grid01"
pagesize=10
title="Employee database"
bind="cfc:mycfcs.employee.getEmployees({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfg
ridsortdirection})"
onChange="cfc:mycfcs.
employee.editEmployees({cfgridaction},{cfgridrow},{cfgridchanged})">
<cfgridcolumn name="Emp_ID" display=false header="ID" />
<cfgridcolumn name="FirstName" display=true header="First Name"/>
<cfgridcolumn name="Email" display=true header="Email"/>
<cfgridcolumn name="Department" display=true header="Department" />
</cfgrid>
</cfform>
866
<html>
<head>
</head>
<body>
<cfform name="mycfform">
First Name: <cfinput type="text" name="firstname" value=""><br>
Last Name: <cfinput type="text" name="lastname" value=""><br>
Domain: <cfinput type="text" name="domain" value=""><br>
E-mail: <cfinput type="text" name="email1" size="30"
bind="{firstname}.{lastname}@{domain}">
</cfform>
</body>
</html>
The following example shows the results of binding to radio buttons and check boxes with the same name attribute but
different id attributes. Notice that because each control has a separate id value that is used in the label tags, you click
the labels to select and deselect the controls.
<html>
<head>
</head>
<body>
<cfform name="myform">
Pick one:
<cfinput id="pickers1" name="pickone" type="radio" value="Apples">
<label for="pickers1">Apples</label>
<cfinput id="pickers2" name="pickone" type="radio" value="Oranges">
<label for="pickers2">Oranges</label>
<cfinput id="pickers3" name="pickone" type="radio" value="Mangoes">
<label for="pickers3">Mangoes</label>
<br>
<cfinput name="pickone-selected" bind="{pickone}"><br />
<br />
Pick as many as you like:
<cfinput id="pickers4" name="pickmany" type="checkbox" value="Apples">
<label for="pickers4">Apples</label>
<cfinput id="pickers5" name="pickmany" type="checkbox" value="Oranges">
<label for="pickers5">Oranges</label>
<cfinput id="pickers6" name="pickmany" type="checkbox" value="Mangoes">
<label for="pickers6">Mangoes</label>
<br/>
<cfinput name="pickmany-selected" bind="{pickmany}"><br />
</cfform>
</body>
</html>
Most applications call a CFC function, or JavaScript function, or use a URL to make an HTTP request (typically to a
CFML page), and pass bind parameters as the function or URL parameters.
The following example uses the same form as the first example in the preceding section, but uses a different bind
expression with the following features:
It uses the keyup events of the name and domain fields to trigger binding. So the e-mail field gets updated each time
that you enter a letter in any of these fields.
867
It calls a CFC, which uses only the first letter of the first name when forming the e-mail address, and forces the
domain name to be all lowercase.
The following example shows the bindapp.cfm page:
<html>
<head>
</head>
<body>
<cfform name="mycfform">
First Name: <cfinput type="text" name="firstname" value=""><br>
Last Name: <cfinput type="text" name="lastname" value=""><br>
Domain: <cfinput type="text" name="domain" value=""><br>
E-mail: <cfinput type="text" name="email"
bind="cfc:bindFcns.getEmailId({firstname@keyup},{lastname@keyup},
{domain@keyup})">
</cfform>
</body>
</html>
Many of the examples in the documentation for ColdFusion Ajax features use binding, including more complex forms
of binding.
The onError function specifies code to handle an HTTP error return. You use this attribute with a URL or CFC bind.
868
The onSuccess function handles a valid return from the function or page and updates the display as required with
the returned information.
Binding a function or request by using the cfajaxproxy tag enables you to perform a server-side action, such as
updating a database by using bind parameter values based on a user action in some control, and then run a specific
action or set of actions in one or more controls based on the server response. Because it uses an onSuccess function
to process the return from the server, this form of binding provides substantially more flexibility than a CFML control
bind parameter. This format also lets you use a control bind parameter for one kind of action, and the cfajaxproxy
tag for a different activity.
For example, if you have a form with an editable cfgrid control and a delete button that a user clicks to delete a grid
row. The application must have the following behaviors:
When the user clicks the delete button two things must happen:
The application must call a mycfc.deleteButton CFC function to delete the row from the database.
The grid must update to remove the deleted row.
When the user edits the grid content, the grid must call a mycfc.update function to update the database.
Implement these behaviors by doing the following:
In the cfgrid tag, specify a bind attribute that uses a bind expression to call a mycfc.update function each time the
user changes the grid contents.
In a cfajaxproxy tag, specify a bind attribute that calls the mycfc.deleterow CFC function, and specify an
onSuccess attribute that calls the ColdFusion.Grid.refresh function to update the displayed grid when the
CFC function returns successfully.
The following complete example shows a simple use of the bind attribute in a cfajaxproxy tag. For the sake of brevity,
the bind expression calls a JavaScript function; as a result, the cfajaxproxy tag cannot use a onError attribute.
869
<html>
<head>
<script language="javascript">
function test(x,y){
return "Hello, " + x + "!";
}
function callbackHandler(result){
alert("Bind expression evaluated. Result: \n" + result);
}
</script>
<cfajaxproxy bind="javascript:test({input1@none},{button1@click})"
onSuccess="callbackHandler">
</head>
<body>
<cfform name="mycfform">
<cfinput type="text" value="" name="input1" size="30">
<cfinput type="button" name="button1" value="Submit">
</cfform>
</body>
</html>
Use the cfajaxproxy tag to create a client-side JavaScript proxy for a CFC and its functions. You then call the
proxy functions in client JavaScript code to access the server-side CFC functions.
Use the cfsprydataset tag to dynamically populate a Spry data set from a URL or a CFC. You then use the data
set to populate Spry dynamic regions. You also use Spry data sets in bind expressions.
Use the cfajaxproxy tag to bind fields of ColdFusion Ajax form controls as parameters to a specific CFC function,
JavaScript function, or HTTP request, and specify JavaScript functions to handle successful or error results. The
function is run each time the event determined by the bind expression occurs.
Use ColdFusion Ajax-based UI tags, such as cftree or cfgrid that automatically get data from CFCs or URLs by
using data binding.
For Information on working with Spry, including how to use the cfsprydataset tag, see Using Spry with
ColdFusion on page 874. For detailed information on using binding, including how to use binding with ColdFusion
UI tags and the cfajaxproxy tag, see Binding data to form fields on page 860. For more information on using the
ColdFusion Ajax-based UI tags, see Using Ajax User Interface Components and Features on page 804.
870
It provides a JavaScript function that corresponds to each CFC remote function. Calling these functions in your
client-side JavaScript code remotely calls the CFC functions on the server.
It provides JavaScript support functions for controlling the communication, which specifies asynchronous result
and error handler callbacks, and sends form data to the server. For detailed information on these functions, see the
cfajaxproxy tag in the CFML Reference.
It manages the interactions between the client and the CFC, including serializing and deserializing JavaScript arrays
and structures to and from JSON format for transmission over the web.
It ensures automatic serialization (into JSON format) and deserialization of CFC return values.
By using a ColdFusion Ajax proxy, any JavaScript code can call the proxied CFC functions. Thus, any Ajax application,
not just one that uses ColdFusion Ajax UI elements, can use dynamic data provided by CFCs. Also, the proxy provides
access to all of the functions in a CFC, not just the single function that you specify in a bind expression.
Creating a JavaScript CFC proxy
The cfajaxproxy tag with a cfc attribute generates a JavaScript proxy that represents a CFC on the web client.
Because a ColdFusion page that uses the cfajaxproxy tag is used as an Ajax client web page, the page typically starts
with the cfajaxproxy tag (or tags), and the remainder of the page consists of the HTML and JavaScript required to
control the display and perform the page logic on the client.
Note: Because JavaScript is case-sensitive, make sure that you match the case of the keys in any ColdFusion structure or
scope that you send to the client. By default, ColdFusion sets variable names and structure element names to alluppercase. (You create structure element names with lowercase characters by specifying the names in associative array
notation, for example, myStruct["myElement"]="value".) The keys for the two arrays in the JSON object that the
ColdFusion SerializeJSON function generates to represent a query are COLUMNS and DATA, for example, not columns
and data.
For more information about creating and using CFC proxies, see the cfajaxproxy tag in the CFML Reference.
Configuring the CFC proxy
The proxy provides several JavaScript functions that you use to control the behavior of the proxy:
You use the setAsyncMode and setSyncMode functions to control the call mode. By default, all calls to remote CFC
functions are asynchronous, the most common synchronization method for Ajax applications.
You use the setCallbackHandler and setErrorHandler functions to specify the functions that handle the results
of successful and unsuccessful asynchronous calls.
Note: For error handling to work properly, select the Enable HTTP Status Codes option on the Server Settings >
Settings page of the ColdFusion Administrator.
You use the setHTTPMethod function to control whether the call uses a GET HTTP request (the default) or a POST
request.
You use the setForm function to prepare the proxy to send full form data to the remote function. This function
causes the proxy to pass each form field as a separate parameter to the CFC function.
871
You use the setReturnFormat function to specify whether to return the result in JSON format (the default), in
WDDX format, or as plain text. Use the setQueryFormat function to specify whether to return a JSON format
query as an object with an array of column names and an array of row arrays, or as an object that corresponds to
the WDDX query format. These functions only effect the format of data returned by ColdFusion. Data sent from
the proxy to the server is always in JSON format.
Submitting data to a CFC
When you use an Ajax CFC proxy, you send to the CFC function any client-side data that can be serialized to JSON
format, not just form data. However, the proxy cannot serialize DOM tree elements because they are wrappers on
native code. Therefore, you cannot use DOM tree elements directly as parameters to a CFC function that you call by
using an Ajax proxy. To ensure correct serialization to JSON for sending to the CFC, use basic JavaScript types only:
array, object, and simple types. Instead of using a DOM element directly, you pass only the specific element attributes
that you require to the CFC function, either individually or in an array or object.
When you use the cfc attribute, you submit form data to the CFC without refreshing the client page by calling the
proxy setForm function before you call a CFC proxy function in your JavaScript. The proxy function then passes all
field values of the specified form to the CFC function. In the CFC function Arguments scope, the argument names are
the form control ID attributes (or, by default, the name attributes) and the argument values are the control values.
Note: You cannot use the setForm function to submit the contents of file fields.
To pass the form parameters to your proxy function, invoke the proxy function immediately after you call the setForm
function. Subsequent proxy function invocations do not get the form parameters.
If you also pass arguments explicitly to the CFC, cfargument tags in the CFC function that specify the explicitly passed
arguments must precede any cfargument tags for the form fields. For example, if you have the following submitForm
JavaScript function:
function submitForm() {
var proxy = new remoteHandler();
proxy.setCallbackHandler(callbackHandler);
proxy.setErrorHandler(errorHandler);
proxy.setForm('myform');
proxy.setData('loggedIn');
}
In this example, userName is the name of a form field. If the cfargument tag for userName preceded the cfargument
tag for the loggedIn explicitly passed variable, the CFC function would not get the value of loggedIn. Your CFC
function can omit cfargument tags for the form fields.
872
<!--- The cfajaxproxy tag creates a client-side proxy for the emp CFC.
View the generated page source to see the resulting JavaScript.
The emp CFC must be in the components subdirectory of the directory
that contains this page. --->
<cfajaxproxy cfc="components.emp" jsclassname="emp">
<html>
<head>
<script type="text/javascript">
// Function to find the index in an array of the first entry
// with a specific value.
// It is used to get the index of a column in the column list.
Array.prototype.findIdx = function(value){
for (var i=0; i < this.length; i++) {
if (this[i] == value) {
return i;
}
}
}
// Use an asynchronous call to get the employees for the
// drop-down employee list from the ColdFusion server.
var getEmployees = function(){
// Create an instance of the proxy.
var e = new emp();
// If you set a callback handler for the proxy, the proxy's calls
// are asynchronous.
e.setCallbackHandler(populateEmployees);
e.setErrorHandler(myErrorHandler);
// The proxy getEmployees function represents the CFC
// getEmployees function.
e.getEmployees();
}
// Callback function to handle the results returned by the
// getEmployees function and populate the drop-down list.
var populateEmployees = function(res)
{
with(document.simpleAJAX){
var option = new Option();
option.text='Select Employee';
option.value='0';
employee.options[0] = option;
for(i=0;i<res.DATA.length;i++){
var option = new Option();
option.text=res.DATA[i][res.COLUMNS.findIdx('FIRSTNAME')]
+ ' ' + res.DATA[i][[res.COLUMNS.findIdx('LASTNAME')]];
option.value=res.DATA[i][res.COLUMNS.findIdx('EMP_ID')];
employee.options[i+1] = option;
}
}
}
// Use an asynchronous call to get the employee details.
// The function is called when the user selects an employee.
var getEmployeeDetails = function(id){
873
874
}
</script>
</head>
<body>
<!--- The form to display the employee drop-down list and
employee data. --->
<form name="simpleAJAX" method="get">
List of Employees:
<select name="employee" onChange="getEmployeeDetails(this.value)">
<script language="javascript">
getEmployees();
</script>
</select>
<br><br>
<span id="empData"></span>
</form>
</body>
</html>
The following component, which gets the data from the data source, must be in a file named emp.cfc in the
components subdirectory of the application directory. The CFC uses the cfdocexamples data source that is installed
with ColdFusion if you install the documentation.
<cfcomponent>
<cfset this.dsn = "cfdocexamples">
<cffunction name="getEmployees" access="remote" returnFormat="json" output="false">
<cfargument name="empid" required="no" type="string" default="0">
<Cfquery name="qryEmp" datasource="#this.dsn#">
select * from Employees
<cfif empid neq 0>
where Emp_ID = #empid#
</cfif>
</Cfquery>
<cfreturn qryEmp>
</cffunction>
</cfcomponent>
ColdFusion tags use Spry data sets directly in bind expressions. Therefore, a ColdFusion form element, such as
cfinput, binds to a field in a dynamic Spry data set, and is updated each time the data set updates, including when
the user selects an item in a Spry control or dynamic region that the data set populates.
To bind to a Spry data set, specify the data set name followed by the path to the specific element that you bind to,
by using standard Spry path syntax. For example, if dsFilters is a Spry data set with a name column, the
{dsFilters.name} bind parameter binds to the value of the current rows name column. The bind parameter
cannot specify an event; the bind expression is re-evaluated each time the selected row in the data set changes. The
following example shows the bind syntax:
<cfinput name="Input1" type="text"
bind="CfC:DataManager.getInData(filter={dsFilters.name})
875
Spry data sets use a CFC function as the data source. To do this, you simply specify the URL of the CFC in the
Spry.Data.XMLDataSet function, just as you would invoke any remote CFC method using a URL. Specify the
method name with a method URL parameter, and pass data to the function in additional URL parameters, as in the
following example:
Spry.Data.XMLDataSet("MyAppMgr.cfc?method=getFilter&filter=scores",
"filters/filter");
The cfsprydataset tag dynamically creates and updates Spry XML or JSON data sets based on ColdFusion form data.
Spry dynamic regions and other elements then use this data to control their display.
The following example shows a cfsprydataset tag that creates a Spry XML data set named dsProducts by calling
the getData.getProductDetails function and passing it the value of the selected name in a cfgrid control. The data
set updates each time the name value changes.
<cfsprydataset
name="dsProducts"
type="xml"
bind="CFC:getData.getProductDetails(prodname={myform:mygrid.name})"
xpath="products/product"
options="{method: 'POST'}"
onBindError="errorHandler">
ColdFusion includes the complete Spry 1.5 framework release in web_root/CFIDE/scripts/ajax/spry directory. For
more information about Spry framework, see www.adobe.com/go/learn_spry_framework_en. For more information,
see the cfsprydataset tag in the CFML Reference.
calls a CFC and passes it a parameter bound to the selected item in the Spry XML data set.
4 It creates a second Spry XML data set by using a cfsprydataset tag that binds to the selected item in the cfgrid
The example lets a user select the genre of books to display: all books, fiction, or nonfiction from a Spry list box
populated from the XML file. The selected genre determines the information displayed by a cfgrid control, and a text
input control shows the selected genre. The selected item in the cfgrid control determines the information that is
displayed in a second Spry dynamic region.
The application consists of the following files:
876
For this example to display images, create an images subdirectory of your application directory that contains images
with the names specified by the BOOKIMAGE column of the cfbookclub database BOOKS table.
The roundtrip.cfm page
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<!--- The screen.css style sheet is provided in the Spry distribution. --->
<link href="screen.css" rel="stylesheet" type="text/css" media="all"/>
<!--- Include the XPath and Spry JavaScript files. --->
<script type="text/javascript"
src="/CFIDE/scripts/ajax/spry/includes/xpath.js"></script>
<script type="text/javascript"
src="/CFIDE/scripts/ajax/spry/includes/SpryData.js"></script>
<!--- Create the dsFilters Spry XML data set used to populate the FiltersList dynamic region
that lists the filters. Call the GridDataManager CFC getFilter method directly from a
Spry XMLDataSet function because no binding is needed. --->
<script>
var dsFilters = new
Spry.Data.XMLDataSet("GridDataManager.cfc?method=getFilter", "filters/filter");
</script>
<!--- Use a cfsprydataset tag with binding to generate a dsProduct Spry data set with details
about the book grid selection. --->
<cfsprydataset
name="dsProduct"
type="xml"
bind="CFC:GridDataManager.getProductDetails(prodname={bookform:bookgrid.TITLE})"
xpath="products/product"
options="{method: 'POST'}"
onBindError="errorHandler">
<!--- Function to handle bind errors. --->
<script language="javascript">
errorHandler = function(code,msg){
alert("Error w/bind occurred. See details below:\n\n" + "Error Code: "
+ code + "\n" + "Error Message: " + msg);
}
</script>
<!--- Specify the size of the FiltersList Spry dynamic region.
By default it would be unnecessarily large. --->
<style type="text/css">
<!-#FiltersList {
height:100px;
width: 150px;
}
-->
</style>
</head>
<body>
<!--- A Spry dynamic region containing repeated ListBoxItem controls.
Each item specifies a filter to use in filling the book list grid.
877
The items are populated by the data from the CFC getFilter method. --->
<div id="FiltersList" spry:region="dsFilters" class="SpryHiddenRegion">
<div spry:repeat="dsFilters" class="ListBoxItemGroup">
<div class="ListBoxItem"
onclick="dsFilters.setCurrentRow('{dsFilters::ds_RowID}');"
spry:selectgroup="feedsList" spry:select="SelectedListBoxItem"
spry:hover="ListBoxItemHover">
{dsFilters::description}
</div>
</div>
</div>
<!--- A ColdFusion form with the book list data grid. --->
<cfform name="bookform">
<!--- Create a book list grid.
Users select the book for which to get details from this grid.
Populate it with the results of the CFC getData method.
Pass the method the value of the name field of the selected
item in the dsfilters Spry dynamic region. --->
<cfgrid name="bookgrid"
format="html"
bind="CfC:GridDataManager.getData(page={cfgridpage},
pageSize={cfgridpagesize},sortCol={cfgridsortcolumn},
sortDir={cfgridsortdirection},filter={dsFilters.name})"
selectMode="browse"
width=400
delete="true"
pageSize=7>
<cfgridcolumn name="TITLE" header="Name" width=200>
<cfgridcolumn name="GENRE" header="Type" width=200>
</cfgrid><br />
<!--- Show the value of the name field of the selected item in the Spry dynamic region.
--->
<cfinput name="filter" bind="{dsFilters.name}">
</cfform>
<hr>
<!--- A Spry dynamic region that uses the dsProduct data set to display information on the
selected product. --->
<div id="RSSResultsList" spry:detailregion="dsProduct" class="SpryHiddenRegion">
<strong>{name}</strong><br>
<img src="images/{bookimage}" alt="product box shot" width="238" height="130"/>
<div>{desc}</div>
</div>
<hr>
</body>
</html>
878
879
<cfoutput>
<cfxml variable="BookDetailsXML" >
<?xml version="1.0" encoding="iso-8859-1"?>
<products>
<product>
<name>#BookDetails.TITLE#</name>
<category>#BookDetails.GENRE#</category>
<bookimage>#BookDetails.BOOKIMAGE#</bookimage>
<desc>#BookDetails.BOOKDESCRIPTION#</desc>
</product>
</products>
</cfxml>
</cfoutput>
<!--- Convert the XML object to an XML string. --->
<cfset xmldata = xmlparse(BookDetailsXML)>
<cfcontent type="text/xml" reset="yes">
<cfreturn xmldata>
</cffunction>
</cfcomponent>
Gets all the client-side JavaScript, CSS, and other files required for Ajax-based features from the
web_root/CFIDE/scripts/ajax directory.
For each application page, imports only the JavaScript files required for the tags that are explicitly included on the page.
In some cases, override these default behaviors.
880
If the ColdFusion client-side files required by all applications, including the files used by cfform tags are in a single
location, you specify the directory in the ColdFusion Administrator > Server Settings > Settings page, Default
CFFORM ScriptSrc Directory field. The directory you specify and its subdirectories must have the same structure
and contents as the CFIDE/scripts directory tree.
If the client-side files required for Ajax features on a specific page are in one location, you use the cfajaximport
tag scriptsrc attribute to specify the source directory. This tag overrides the setting in the administrator, and does
not affect the files used for standard cfform features. The directory you specify must have an ajax subdirectory with
the same structure and contents as the CFIDE/scripts/ajax directory tree.
You specify the client-side source directory for a specific form in the cfform tag scriptsrc attribute. This setting
overrides any cfajaximport tag setting for the form and its child controls. The directory you specify and its
subdirectories must have the same structure and contents as the CFIDE/scripts directory tree.
If you require multiple resource locations for a single page, make sure that each JavaScript file is imported only once
on a page, the first time it is required. Therefore, you cannot use different copies of one JavaScript file on the same page.
To prevent problems, ColdFusion generates an error if you specify more than one scriptsrc attribute on a page.
Therefore, if multiple forms require custom client-side resource files, specify their location in a single cfajaximport
tag, not in scriptsrc attributes in the cfform tags.
Specify the CSS file location
Use the cfajaximport tag cssSrc attribute to specify the location of a directory that contains only the CSS files that
control the style of ColdFusion Ajax-based controls. This attribute overrides any scriptsrc value in determining the
CSS file location. Therefore, you could use the CSS files in the scriptsrc directory tree for most pages, and specify a
cssSrc attribute on selected application pages that require a custom look.
For detailed information on how to use the scriptsrc and cssSrc attributes, and requirements for the contents of
the specified directory, see the cfajaximport tag in the CFML Reference.
881
If you use a ColdFusion Ajax-based tag on a page that you specify by using a source or bind attribute in a container
tag, such as cfdiv, cflayoutarea, cfpod, or cfwindow. Place a cfajaximport tag on the page that has the
container tag and use the tags attribute to specify the Ajax feature tags that are on the other pages. (You do not
have to do this for any tags that are also used on the page with the source attribute.)
For detailed information on importing tag-specific JavaScript files, see the cfajaximport tag in the CFML Reference.
882
If the requested return format is JSON and the function returns a query, ColdFusion serializes the query into a JSON
object in either of the following formats:
As a JSON object with two entries: an array of column names, and an array of column data arrays.
These entries are returned in the following situations:
By default
If you specify an HTTP URL parameter of queryFormat="row"
If you use the cfajaxproxy tag and call the proxy objects setReturnFormat function with a parameter value
of row
ColdFusion client-side binding and proxy code automatically converts this data into JavaScript that is consumed
directly by HTML grids.
As a JSON object with three entries: the number of rows, an array of column names, and an object where each key
is a column name and each value is an array with the column data
These entries are returned in the following situations:
ColdFusion client-side binding and proxy code does not convert column format data into JavaScript that is
consumed directly by HTML grids. However, use this format with the cfajaxproxy tag, because you can refer to
the returned data by using the column names directly. For example, if a CFC function returns a query with user
data, you get the user names in your JavaScript by specifying values such as userData.firstName[0] and
userData.lastName[0].
For more information, see the SerializeJSON function in the CFML Reference.
Using JSON
JSON (JavaScript Object Notation) is a lightweight JavaScript-based data interchange format for transmission between
computer systems. It is a much simpler format than XML or WDDX, and is an efficient, compact format for
transmitting data required for Ajax applications. ColdFusion Ajax bind expressions that use CFCs tell the CFC
function to send the data in JSON format by including a returnformat="json" parameter in the HTTP request, and
automatically handle the JSON-formatted result.
JSON represents objects by using { key : value , key : value... } notation, and represents arrays in standard [ value ,
value... ] notation. Values can be strings, numbers, objects, arrays, true, false, or null. Therefore, you can nest arrays
and objects inside each other. For a detailed specification of the JSON format, see www.JSON.org.
Although ColdFusion Ajax-based controls and the cffunction tag interoperate transparently, without you
converting anything to JSON format, other applications can take advantage of JSON format data. Many public feeds
are now available in JSON format. For example, the Yahoo! search interface returns a JSON data set, del.icio.us
provides JSON feeds showing your posts and tags, and Blogger feeds are available in JSON format. You dont have to
use Ajax to display these feeds; use standard ColdFusion tags and functions to display the results.
The following CFML functions support using JSON format in server-side code:
DeserializeJSON
SerializeJSON
IsJSON
883
For more information about these functions and examples, see the CFML Reference.
The following example shows how to use ColdFusion JSON functions in a non-Ajax application. It does a Yahoo
search for references to "ColdFusion Ajax" and displays these results:
Serialized JSON
10
10
012
012
10.25
10.25
10.25E5
1025000.0
10.25E-5
1.025E-4
-10
-10.0
-10.25
-10.25
Note: To remove the quotes in the returned value, for positive integers and integers within quotes, set the jvm argument
json.numberasdouble totrue . However, negative integers such as -10 will still be serialized to -10.0 even if
json.numberasdouble=true.
884
Select the Enable Ajax Debug Log Window option on the ColdFusion Administrator > Debugging & Logging >
Debug Output Settings page. To view exception messages in the logging window, select the Enable Robust
Exception Information option on the Debug Output Settings page.
Make sure that the IP address of the system where you do the debugging is included on the ColdFusion
Administrator > Debugging & Logging > Debugging IP List page of the ColdFusion Administrator. By default this
list includes only 127.0.0.1.
Display logging information for a page
To display the logging window when you request a CFML page in the browser, specify an HTTP parameter of cfdebug
in the URL when you request a page, as in the following URL:
http://localhost:8500/myStore/products.cfm?cfdebug
After the debug log window appears, it continues running until you navigate to a new page in the browser. The logging
window includes options that let you filter the messages by either or both of the following criteria:
Severity
Category
You can select to display logging information at any combination of four levels of severity: debug, info, error, and
window. The specific logging function that you call determines the severity level.
The logging window always displays options to filter the output by using standard categories: bind, global, http,
LogReader, and widget. (For information on these categories, see Standard ColdFusion logging messages on
page 885.) It also displays a filter option for each custom category that you specify in a ColdFusion logging call.
ColdFusion does not limit the number of categories you create, but create only as many categories as you require to
debug your application effectively.
885
Logging information
You call the following JavaScript functions to send information to the logger. In most cases, the function corresponds
to a severity level, as follows:
Function
Severity
Purpose
ColdFusion.Log.debug
debug
ColdFusion.Log.dump
debug
ColdFusion.Log.error
error
ColdFusion.Log.info
info
You cannot generate a window-level message. This level is reserved for messages generated by the log reader window,
including information about JavaScript errors in the log function calls.
When you call a logging function, you specify a message and a category.
The message can include JavaScript variables and HTML markup, such as bold text and line breaks.
The category is a short descriptive name. ColdFusion generates a check box option for each category to filter the
logging window output. This parameter is optional; the default value is global. You can specify a standard
ColdFusion category or a custom category.
To log information for a page, you must have a ColdFusion Ajax tag on the page, or use the cfajaximport tag. The
cfajaximport tag does not require any attributes to enable logging.
The following logging function generates an error level, Pod A category log message:
ColdFusion.Log.error("<b>Invalid value:</b><br>" + arg.A, "Pod A");
Description
global
(the default) Messages that are not logged from within the ColdFusion Ajax libraries, for example, initialization
of the logging infrastructure.
http
Information about HTTP calls and their responses, including the contents of HTTP requests and information on
CFC invocations and responses.
LogReader
bind
widget
886
Preventing errors
The following rules and techniques help you prevent errors in your applications:
To ensure that your code works properly, make sure that all your pages, including dynamically loaded content and
pages that contain dynamic regions, have valid html, head, and body tags, and that all script tags are located in
the page head. This is important for any page with ColdFusion Ajax tags and script tags, where it ensures that the
script code is processed and that code is generated in the correct order. It also prevents problems in some browsers,
such as Internet Explorer.
All JavaScript function definitions on pages that you include dynamically, for example by using a bind expression,
the ColdFusion.navigate function, or a form submission within a ColdFusion Ajax container tag, must have the
following syntax format:
functionName = function(arguments) {function body}
Function definitions that use the following format might not work:
function functionName (arguments) {function body}
However, Adobe recommends that you include all custom JavaScript in external JavaScript files and import them
on the applications main page, and not write them in-line in code that you get dynamically. Imported pages do not
have this restriction on the function definition format.
In a CFM page, if you call a JavaScript function present in a file that is bound to the page, ensure that you do not
use the keyword var while declaring the function. var declares a function-local scope variable. Therefore, you
cannot invoke the JavaScript function from the parent page.
As a general rule, the id attributes or name attributes, when you do not specify id attributes, of controls should be
unique on the page, including on any pages that you specify in source attributes. Exceptions to this rule include
the following:
You can use the same name attribute for all options in a radio button group. Bind expressions get information
about the selected button.
You can use the same name attribute for check boxes in a group if you want a single bind expression to get
information about all selected controls in the group.
If you have multiple similar forms on a page, you might have controls in each form with the same name or ID.
You specify the individual controls in bind expressions by including the form name in the bind parameter.
Do not use an Application.cfc onRequestEnd function or onRequestEnd.cfm page that creates output in
applications that use the cfajaxproxy tag or bind expressions that call CFC functions to get data. ColdFusion Ajax
features normally require that all returned data from the server must be in JSON format; the onRequestEnd
method onRequestEnd.cfm page appends any output as non-JSON information to the end of the returned data.
By default, all ColdFusion structure element names are in all uppercase characters. Therefore, your client-side Ajax
code, such as an onSuccess function specified by a cfajaxproxy tag, must use uppercase letters for the returned
objects element names if you do not explicitly ensure that the element names are not all uppercase. (You can create
structure element names with lowercase characters by specifying the names in associative array notation, for
example, myStruct["myElement"]="value".)
ColdFusion Ajax controls throw JavaScript errors if badly formed HTML causes errors in the browser DOM
hierarchy order. One example of such badly formed HTML is a table that contains a cfform tag, which in turn
contains table rows. In this situation, you place the table tag inside the cfform tag.
For browser-specific issues and other issues that could affect application appearance and behavior, see the ColdFusion
Release Notes on the Adobe website at www.adobe.com/go/learn_cfu_docs_en, and the ColdFusion Developer Center
on the Adobe website at www.adobe.com/go/prod_techarticles.
887
Improving security
ColdFusion includes several capabilities that help to ensure the security of Ajax application. Also, the ColdFusion
Administrator disables output to the client-side logging window by default (see Enable logging output on page 884).
To prevent cross-site scripting, you cannot use remote URLs in code that executes on the client. For example, if you
use a URL such as http://www.myco.com/mypage.cfm in a cfwindow tag source attribute, the remote page does
not load in the window and the window shows an error message. If you must access remote URLs, do so in CFML
code that executes on the server, for example, by using a cfhttp tag on the page specified by a source attribute.
When a CFC function returns remote data in JSON format, by default, the data is sent without any prefix or
wrapper. To help prevent cross-site scripting attacks where the attacker accesses the JSON data, you can tell
ColdFusion to prefix the returned data with one or more characters. You can specify this behavior in several ways.
The value of an item in the following list is determined by the preceding item in this list:
1 In the Administrator, enable the Prefix Serialized JSON option on Server Settings > Settings page (the default
value is false). You can also use this setting to specify the prefix characters. The default prefix is //, which is
the JavaScript comment marker that turns the returned JSON code into a comment from the browsers
perspective. The // prefix helps prevent security breaches because it prevents the browser from converting the
returned value to the equivalent JavaScript objects.
2 Set the Application.cfc file This.secureJSON and This.secureJSONPrefix variable values, or set the
cfapplication tag secureJSON and secureJSONPrefix attributes.
3 Set the cffunction tag secureJSON attribute. (You cannot use the cffunction tag to set the prefix.)
As a general rule, use one of these techniques for any CFC or CFML page that returns sensitive data, such as
credit card numbers.
When you use any of these techniques, the ColdFusion Ajax elements that call CFC functions, including bind
expressions and the CFC proxies created by the cfajaxproxy tag, automatically remove the security prefix
when appropriate. You do not have to modify your client-side code.
ColdFusion provides capabilities that help prevent security attacks where an unauthorized party attempts to
perform an action on the server, such as changing a password. Use the following techniques to ensure that a request
to a CFML page or remote CFC function comes from a ColdFusion Ajax feature, such as a bind expression or CFC
proxy, that is a valid part of your application:
In the cffunction tag in a CFC function that returns data to an Ajax client, specify a verifyClient attribute
with a value of yes.
At the top of a CFML page or function that is requested by a ColdFusion Ajax client, call the VerifyClient
ColdFusion function. This function takes no parameters.
The VerifyClient function and attribute tell ColdFusion to require an encrypted security token in each request.
To use this function, enable client management or session management in your application; otherwise, you do not
get an error, but ColdFusion does not verify clients.
Enable client verification only for code that responds to ColdFusion Ajax client code, because only the ColdFusion
Ajax library contains the client-side support code. Enabling client verification for clients other than ColdFusion
Ajax applications can result in the client application not running.
As a general rule, use this function for Ajax requests to the server to perform sensitive actions, such as updating
passwords. Typically, do not enable client verification for public APIs that do not need protected, search engine web
services. Also, do not enable client verification for the top-level page of an application, because the security token
is not available when the user enters a URL in the browser address bar.
888
Programming effectively
The following recommendations help improve or customize your ColdFusion Ajax application.
Use the AjaxOnLoad function, which specifies a JavaScript function to run when the page loads, to perform any
initialization actions that are required for a page to function properly. Use the AjaxOnLoad function to call
functions when a page is loaded in a container tag. One use for this function could be on a page that pops up a login
window if the user is not already logged in when it displays. You can use the AjaxOnLoad function to specify a
JavaScript function that determines the login status and pops up the window only if necessary.
Use the following ColdFusion JavaScript functions to access the Ext JS or Yahoo YUI JavaScript library objects that
underlie border and tab style cflayout controls, cfwindow controls, and HTML format cfgrid and cftree
controls. Then use the raw object to modify the displayed control.
ColdFusion.Layout.getBorderLayout
ColdFusion.Grid.getGridObject
ColdFusion.Layout.getTabLayout
ColdFusion.Tree.getTreeObject
ColdFusion.Window.getWindowObject
For documentation on the objects and how to manage them, see the Ext documentation at
extjs.com/deploy/ext/docs/ and the Yahoo toolkit documentation at developer.yahoo.com/yui/.
889
Using cfdocument
In addition to the existing functionality, the cfdocumenttag lets you convert Word documents and PowerPoint
presentations to PDF. All versions of Microsoft Word and Microsoft PowerPoint from 97 to 2003 are supported.
Note: If you do not specify the filename attribute, the converted PDF opens in a browser.
890
Using cfpresentation
The cfpresentation tag is the parent tag for one or more cfpresentationslide tags, where you define the content
for the presentation, and the cfpresenter tags, which provide information about the people presenting the slides.
You use the cfpresentation tag to convert a PowerPoint presentation to an Adobe Connect presentation or HTML.
Browsers like Internet Explorer, Mozilla Firefox, and Safari are all compatible with the conversion from PPT to a
Connect presentation or HTML.
For complete information about cfpresentation, and cfpresentationslide, see CFML Reference.
Examples
The following example converts a PowerPoint presentation to an Adobe Connect presentation.
<cfpresentation
title="my presentation"
directory="C:\presentations\"
overwrite=true>
<cfpresentationslide
src="#ppttemplate#backgrounds.ppt"
slides="1">
</cfpresentationslide>
<cfpresentationslide
duration="4"
video="video1.flv">
Sample slide
</cfpresentationslide>
</cfpresentation>
891
<cfpresentation
title = "text string"
format= "ppt"
destination="#generated#html_to_ppt_01.ppt"
backgroundColor = "YELLOW"
overwrite = "yes">
<cfpresentationslide
Title="Q1 Sales Figures"
duration="14">
892
<cfpresentation
title="my presentation"
directory="C:\presentations"
overwrite=true>
<cfpresentationslide
src="#ppttemplate#backgrounds.ppt"
slides="1-3,5">
</cfpresentationslide>
<cfpresentationslide
duration="4"
video="video1.flv">
Sample slide
</cfpresentationslide>
</cfpresentation>
Using cfspreadsheet
The cfspreadsheet tag lets you manage Excel spreadsheets. The tag lets you do the following:
Read a spreadsheet file (XLS file) and store it in a ColdFusion spreadsheet object, query, CSV string, or HTML
string.
Write a single sheet to a new XLS from a query, ColdFusion spreadsheet object, or CSV string variable.
Add a sheet to an existing XLS file.
Use the spreadsheet functions to manipulate rows and columns in a spreadsheet and the data in the rows and columns.
You can also specify and get comments, values, and formulas for a cell in the spreadsheet.
Microsoft Office Excel 2007 is supported by cfspreadsheet and all the spreadsheet functions except the following:
SpreadSheetAddSplitPane
SpreadSheetAddFreezePane
For detailed information about cfspreadsheet and all the spreadsheet functions, see CFML Reference.
Examples
The following example reads the spreadsheet file - SingleSheet.xls and stores the spreadsheet data in a CSV string.
<cfspreadsheet action = "read"
format="csv"
src="C:\documents\SingleSheet.xls"
name="csvvar"
rows="1-4,5,6,7-8">
<cfoutput>#csvvar#</cfoutput>
The following example reads the spreadsheet file - template_02.xls and stores the spreadsheet data in a query.
893
<cfspreadsheet
action = "read"
src="C:\dcuments\template_02.xls"
query="excelquery"
sheet="1"
rows="1-3,4-5"
columns="1,4">
<cfoutput
query="excelquery"
startrow="1"
maxrows="#excelquery.recordcount#">
#excelquery.col_1#
#excelquery.col_2#
</cfoutput>
The following example reads a spreadsheet file - template_08_Charts_Graph.xls and stores the spreadsheet data in an
HTML string.
<cfspreadsheet
action = "read"
format="html"
src="C:\documents\template_08_Charts_Graph.xls"
name="report1"
rows="5-11"
columns="1-6">
<cfoutput>
#report1#
</cfoutput>
The following example uses data from a query and writes it to a single sheet in the spreadsheet file - SingleSheet1.xls
<cfquery
name="excelquery"
datasource="cfdocexamples">
SELECT PARKNAME, REGION, STATE FROM Parks WHERE STATE='WI'
ORDER BY ParkName, State
</cfquery>
<cfspreadsheet
action = "write"
filename="C:\SingleSheet1.xls"
query="excelquery"
overwrite="true">
894
Format
CFML Tag
OpenOffice installation
From
To
PPT
Connect Presentation
cfpresentation
optional
PPT
HTML
cfpresentation
optional
PPT
cfdocument
optional
HTML
PPT
cfpresentation
not required
Excel
HTML
cfspreadsheet
not required
Excel
Query
cfspreadsheet
not required
Excel
In-memory Variable
cfspreadsheet
not required
Query
Excel
cfspreadsheet
not required
In-memory variable
Excel
cfspreadsheet
not required
Word
cfdocument
required
SharePoint integration
You can use ColdFusion with Microsoft Windows SharePoint Services 2.0 or 3.0, and Microsoft Office SharePoint
Portal Server 2003 or Microsoft Office SharePoint Server 2007. You can integrate ColdFusion applications with
SharePoint features that are exposed as web service actions.
Using cfsharepoint
Sharepoint integration with ColdFusion helps you dynamically manage user lists, views, and groups; work with images
and document workspaces; and use search effectively. The cfsharepoint tag lets you create new lists, retrieve list
items, and update list items on the SharePoint server.
The following example shows how to create a picture library list called "getpics".
895
<cfsharepoint
action="addlist"
login="#login#"
params="#{ listname ="getpics",
description="This a picture library list",
templateId= "109 " }#"/>
<! --- Creates a folder within the picture library list>
< cfsharepoint
action ="create new folder"
login= "#login#"
name="collection1"
params="#{strListName="getpics",
strParentFolder=""}#"/>
<!--- Uploads pictures to the folder that you created --->
<cfscript>
myimage = filereadbinary(expandpath("Bird.jpg"));
//convert the image into byte array to pass as input for "upload" action.
</cfscript>
<cfsharepoint
action="upload" login="#login#"
params="#{strListName="testpics",
strfolder="Collection1",
bytes="#myimage#",
filename="bird.jpg",
fOverwriteifexist=true}#"/>
<!--- Rotates the picture downloaded from the SharePoint server.--->
<cfsharepoint
name ="result1"
action="download"
login="#login#"
params="#{strListName="getpics",
strfolder="New Folder",
itemFileNames=["bird.jpg"],type=1,
fFetchoriginalIfNotAvailable=true}#"/>
<cfimage
action="rotate"
source="#result1.file#"
isbase64="yes"
angle="45"
name="temp"
destination="bird.jpg"
overwrite="yes"/>
<cfscript>
baseimage = filereadbinary(expandpath("bird.jpg"));
//convert the image into byte array to pass as input for "upload" action.
</cfscript>
<!--- Uploads the rotated image back to the SharePoint server --->
<cfsharepoint
action="upload"
login="#login#"
params="#{strListName="getpics",strfolder="Collection1",
bytes="#baseimage#",filename="bird.jpg",fOverwriteifexist=true}#"/>
To check and ensure that all the updates are made, you can retrieve the list items using code like the following:
896
<cfsharepoint
action="getimaginglistitems"
login="#login#" name="result"
params="#{strListName="getpics",strFolder="#result3.title#"}#"/>
<cfloop array="#result.Library#" index="n">
<cfif n.ows_FileLeafRef contains "temppicrotate.jpg">
SUCCESS
<cfbreak>
</cfif>
</cfloop>
Web Part.
Note: In a Multiserver installation on the Macintosh platform, SharePoint does not work properly if the tools.jar file is
present in WEB-INF/cfusion/lib. In this case, you see the following error message:"coldfusion.jsp.JavaCompilers
UnknownCompiler: Unable to run the internal Java compiler: java.lang.NoClassDefFoundError:
javax/tools/StandardJavaFileManager. To overcome this issue, copy the tools.jar file to a backup directory and delete
the tools.jar file from WEB-INF/cfusion/lib.
Web Parts support only the native single sign-on solution; other pluggable single sign-on services are not
supported.
Only single sign-on credentials are passed to the ColdFusion application. The ColdFusion application must have
the necessary logic to retrieve the credentials and login to the application.
897
Deploy the CF9SSOWebPart.wsp Web Part for Microsoft Office SharePoint Server 2007
To configure single sign-on for Microsoft Office SharePoint Server 2007, deploy the CF9SSOWebPart.wsp file to the
SharePoint server.
1 Copy the CF9SSOWebPart.wsp file to the BIN folder within the Web Server extensions. It is normally located at
Files\Microsoft Shared\Web Server Extensions\12\BIN and enter the following commands, as required.
To delete the solution if it is already present:
STSADM.EXE -o deletesolution -name CF9SSOWebPart.wsp -override
Deploy the CF9SharepointSSOCab.CAB Web Part for Microsoft Office SharePoint Portal
Server 2003
To configure single sign-on for Microsoft Office SharePoint Portal Server 2003, deploy the CAB file CF9SharepointSSOCab.CAB
1 Copy the CF9SharepointSSOCab.CAB to the BIN folder within the Web Server extensions. It is normally located
898
3 From the CF9SharepointSSOCab.CAB file, copy the template file CFSSO.aspx to the CFSharePointSSO folder that
Extensions\60\bin and enter the following command to add the CAB file:
stsadm.exe -o addwppack -filename CF9SharepointSSOCab.CAB -globalinstall
If the CAB file exists, delete the CAB file and then enter the command to add the CAB file as follows:
stsadm.EXE -o deletewppack -name CF9SharepointSSOCab.CAB
stsadm.exe -o addwppack -filename CF9SharepointSSOCab.CAB -globalinstall
Web Parts > Browse > Virtual Server Gallery. Then add the Web Part to the Web Parts list.
5 After adding the CFSharepointSSO Web Part, click the Tools pane and enter the following details.
899
A local host: A portal can access portlets on the same computer where JBoss Portal server exists.
A remote host: A portal can access portlets deployed on a remote ColdFusion server instance.
Prerequisites
Before you start developing ColdFusion portlets, you must:
For example, the following HelloPortlet.cfc extends this package and defines the doView() and doHelp()
methods:
900
<cfcomponent extends="CFIDE.portlets.ColdFusionPortlet">
<cffunction name="doView" returntype="void" output="true">
<cfargument name="renderRequest" type="any" required="true" hint="A
javax.portlet.RenderRequest java object">
<cfargument name="renderResponse" type="any" required="true" hint="A
javax.portlet.RenderResponse java object">
<cfoutput>
Hello World ColdFusion Portlet
</cfoutput>
</cffunction>
<cffunction name="doHelp" returntype="void" output="true">
<cfargument name="renderRequest" type="any" required="true" hint="A
javax.portlet.RenderRequest java object">
<cfargument name="renderResponse" type="any" required="true" hint="A
javax.portlet.RenderResponse java object">
<h1>ColdFusion Help</h1>
<p>This is a Help message for the Hello Portlet.</p>
</cffunction>
</cfcomponent>
2 Save HelloPortlet.cfc in
<jboss_server_home>\server\default\deploy\cfusion.ear\cfusion.war\portlets\hello.
3 Define HelloPortlet.cfc in portlet.xml, which is located in the WEB-INF folder of ColdFusion web root. The
portlet.xml file looks similar to the following:
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0">
<portlet>
<description xml:lang="en">This Portlet is a Hello World CF Portlet</description>
<portlet-name>ColdFusionPortlet</portlet-name>
<display-name xml:lang="en">CF Hello Portlet</display-name>
<portlet-class>coldfusion.portlet.ColdFusionPortlet</portlet-class>
<init-param>
<name>cfcName</name>
<value>portlets.hello.HelloPortlet</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<portlet-info>
<title>ColdFusion Hello World Portlet</title>
</portlet-info>
</portlet>
</portlet-app>
The portlet is defined and registered for portlet definition, with targeted cfcName defined as the INIT parameter.
The INIT parameter value must be from the web root of ColdFusion.
4 Run the JBoss server by running one of the following commands:
On UNIX
901
<JBoss_home>/bin/run.sh
On Windows
<JBoss_home>\bin\run.bat
By default JBoss only binds to localhost. You can have it bind to any IP address by running bin/run.sh -b
0.0.0.0 on UNIX or bin/run.bat -b 0.0.0.0 on Windows.
5 Launch the JBoss portal server. By default, JBoss binds to port 8080, so launch the server using the URL:
http://<matching_IP>:<port>/portal/.
For example: http://127.0.0.1:8080/portal.
6 Log in to the portal by clicking the login link in the upper-right corner. The default credentials are admin/admin.
7 Click the Admin option in the upper-right corner.
8 Click the Portlet Definitions tab. The portlet name, CF HelloPortlet is listed here.
902
Creating a portal
903
16 From the Portlet instance associated with this Window list, select the portlet instance you created in step 10.
904
17 In the Page Layout section, click Add for the center region or left region to add the portlet container in the required area.
18 Go back to the Portal Objects > Portals page and select Make Default option to set the new portal as default.
19 Click the Portal option on the upper-right corner to view the new portal page containing the portlet.
WSRP Producer: The Web Service Response Protocol (WSRP) is used to create the producer of the WSDL. A
WSRP producer can be any ColdFusion standalone, multiserver, or J2EE instance.
WSRP Consumer: Portlets are exposed as web services, which are then consumed by the portal server (JBoss).
905
On UNIX
bin/run.sh
On Windows
bin\run.bat
By default JBoss only binds to localhost. You can have it bind to any IP address by running bin/run.sh -b
0.0.0.0 on UNIX or bin\run.bat -b 0.0.0.0 on Windows.
2 Launch the JBoss portal server. By default, JBoss binds to port 8080, so launch the server using the URL:
http://localhost:8080/portal/.
3 Log in to the portal by clicking the login link in the upper-right corner. The default credentials are admin/admin.
4 Click the Admin option in the upper-right corner.
5 Click the WSRP tab.
6 Specify the WSRP consumer name, such as wsrp-test in the Create a Consumer Named box.
7 Click Create Consumer.
8 On the next page, specify the WSDL URL of the WSRP producer:
http://<WSRPProducer_IP>:<port>/<context_root>/WSRPProducer?wsdl
9 Click Refresh & Save. If successful, the following message appears
906
Description
Syntax
doView()
doHelp()
doEdit()
ProcessAction
()
Init()
processEvent
907
Portlet modes
Portal servers typically allow three portlet modes: View, Edit, and Help.
The View mode is the default state when rendering a portlet. The portlet window has links in the title bar that enable
you to change the mode to Help or Edit.
To add a Help mode view, add the doHelp() with the same signature as the doView() function.
To support the edit mode create the doEdit().
Portlet title
To set the portlet title, add a method to the CFC called getTitle as follows:
<cffunction name="getTitle" returntype="string" output="false" access="public">
<cfargument name="renderRequest" type="any" required="true" hint="A
javax.portlet.RenderRequest java object">
<cfreturn "My ColdFusion Portlet">
</cffunction>
Portlet scope
The ColdFusion portlet toolkit defines the variable request.portlet. It contains the following structures:
request.portlet.parameters - Parameters of the Portlet Request
request.portlet.attributes - attributes of the Portlet Request
request.portlet.properties - properties of the Portlet Request
908
When the form is submitted, the portal container calls the processAction() method in your CFC. So, add this
method as follows:
<cffunction name="processAction" returntype="void" access="public" output="false"
hint="Called by the portlet container to allow the portlet to process an action request.">
<cfargument name="actionRequest" type="any" required="true" hint="A
javax.portlet.ActionRequest java object">
<cfargument name="actionResponse" type="any" required="true" hint="A
javax.portlet.ActionResponse java object">
<cfif IsDefined("request.portlet.parameters.action_value")>
<!--- do something with this value, such as update your database --->
</cfif>
</cffunction>
Examples
The following examples show how you can configure portlets. You can add the following code to the doView()
method depending on whether you are configuring the portlet on a local or remote server.
WSRP:
<cfdump var = #renderRequest.getAttribute("javax.portlet.userinfo")#>
To display PDF:
<cfdocument format="pdf" src="http://www.google.com" filename="cfdoc1.pd f "
overwrite="true">
</cfdocument>
<cfset pdfURL = getPortletResponse().encodeURL(getPortletRequest().getContextPath() &
"/<path of pdf>/cfdoc1.pdf")>
<cfoutput>
<object data="#pdfURL#" type="application/pdf" width="600" height="400">
</object>
</cfoutput>
909
To display Ajax components, all the URLs used in portlets must be encoded.
CFPOD:
<cfset sourceURL = getPortletResponse().encodeURL(getPortletRequest().getContextPath() &
"/<path to cfm>/expandpath.cfm")>
<cfpod name="pod01" source="#sourceURL#" height="500" width="300" title="Example CFPod"/>
expandpath:
<cfoutput>#ExpandPath("./")#</cfoutput>
CFWINDOW:
<cfset sourceURL = getPortletResponse().encodeURL(getPortletRequest().getContextPath() &
"/<path to cfm>/expandpath.cfm")>
<cfwindow title="Test Window" name="myWindow" width="200" height="200" initShow="true"
source="#sourceURL#">
</cfwindow>
JSR-286 Support
ColdFusion 9 also supports JSR-286 specifications. In portlets there are three types of requests: action, event, and
render. A portlet first handles an action request, and then an event request, and only after that, it would render any
request.
Some of the capabilities of JSR-286 include the following:
This code defines an event named cf:HelloEvent, where cf refers to the namespace and HelloEvent is the local name.
Its type is defined by the <value-type> tag. These event definitions require you to use qname to uniquely identify the
event.
Now add the events to specific portlets, which are either going to publish (generate) an event or process (consume) an
event. You add this information to portlet.xml as well.
<supported-publishing-event> tag is used to publish an event.
<supported-publishing-event>
<qname xmlns:cf="http://adobe.com/coldfusion/portlet/example">cf:HelloEvent</qname>
</supported-publishing-event>
</portlet>
910
Portlet definition can have both publishing and processing tags. portlet.xml file has event definition, publishing
event, and processing event tags, as its portlets create and consume events.
911
Using filters
Filter definition and mapping in portlet.xml
<filter>
<filter-name>Example ColdFusion Filter</filter-name>
<filter-class>coldfusion.portlet.ColdFusionPortletFilter</filter-class>
<lifecycle>RENDER_PHASE</lifecycle>
<lifecycle>EVENT_PHASE</lifecycle>
<lifecycle>RESOURCE_PHASE</lifecycle>
<lifecycle>ACTION_PHASE</lifecycle>
<init-param>
<name>cfcName</name>
<value>portlets.filter.ExampleFilter</value>
</init-param>
</filter>
ExampleFilter.cfc:
The following is the ExampleFilter.cfc mentioned in the portlet.xml.
912
<cfcomponent extends="CFIDE.portlets.filter.ColdFusionPortletFilter">
<cffunction name="doRenderFilter" returntype="void">
<cfargument name="renderRequest">
<cfargument name="renderResponse">
<cfargument name="filterChain">
<cflog file="portlet-filter" type="information" text="doRenderFilter() invoked">
<!--- call the next filter in the chain --->
<cfset arguments.filterChain.doFilter(arguments.renderRequest,
arguments.renderResponse)>
</cffunction>
<cffunction name="doActionFilter" returntype="void">
<cfargument name="actionRequest">
<cfargument name="actionResponse">
<cfargument name="filterChain">
<cflog file="portlet-filter" type="information" text="doActionFilter() invoked">
<!--- call the next filter in the chain --->
<cfset arguments.filterChain.doFilter(arguments.actionRequest,
arguments.actionResponse)>
</cffunction>
<cffunction name="doResourceFilter" returntype="void">
<cfargument name="resourceRequest">
<cfargument name="resourceResponse">
<cfargument name="filterChain">
<cflog file="portlet-filter" type="information" text="doResourceFilter() invoked">
<!--- call the next filter in the chain --->
<cfset arguments.filterChain.doFilter(arguments.resourceRequest,
arguments.resourceResponse)>
</cffunction>
<cffunction name="doEventFilter" returntype="void">
<cfargument name="eventRequest">
<cfargument name="eventResponse">
<cfargument name="filterChain">
<cflog file="portlet-filter" type="information" text="doEventFilter() invoked">
<!--- call the next filter in the chain --->
<cfset arguments.filterChain.doFilter(arguments.eventRequest,
arguments.eventResponse)>
</cffunction>
</cfcomponent>
4 Add portlets to the /portlets directory. Add portlet entries to portlet.xml, present at:
cfusion.war/WEB-INF/portlet.xml
913
portlet.xml
7 Create a portal page and add the portlets.
914
Description
cfpdfform
Reads data from a form and writes it to a file or populates a form with data from a data source.
cfpdfformparam
A child tag of the cfpdfform tag or the cfpdfsubform tag; populates individual fields in PDF forms.
cfpdfsubform
A child tag of the cfpdfform tag; creates the hierarchy of the PDF form so that form fields are filled
properly. The cfpdfsubform tag contains one or more cfpdpformparam tags.
The following table describes a few of the tasks that you can perform with PDF forms:
915
Task
populate action of the cfpdfform tag with the destination attribute not
specified
Write PDF form output to an XML file
cfprint tag
Write data extracted from a PDF form submission to a PDF source="#PDF.Content#" for the populate action of the cfpdfform tag,
file
and the destination attribute
Write data in a form generated in LiveCycle to an XDP file
cfdump tag determines the structure of the form data; map the form fields to the
output fields
Flatten forms generated in Acrobat (not used forms
generated in LiveCycle)
cfpdf
For more information, see Flattening forms created in Acrobat on page 941.
For forms created in LiveCycle, you have the option to write the output to an XML Data Package (XDP) file rather than
a PDF file. For more information, see Writing LiveCycle form output to an XDP file on page 920.
Note: If you do not specify a destination, the populate action displays the populated PDF form in a browser window.
916
When you populate a form with an XML data file, ensure that the XML data is in the appropriate format. The format
of the XML data file differs based on whether it was generated from Acrobat or LiveCycle. Acrobat generates an XML
Forms Data Format (XFDF) file format. The following example shows the XFDF format:
<?xml version="1.0" encoding="UTF-8"?>
- <xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
- <fields>
- <field name="textname">
<value>textvalue</value>
</field>
- <field name="textname1">
<value>textvalue1</value>
</field>
</fields>
</xfdf>
Forms created in LiveCycle require an XML Forms Architecture (XFA) format. The following example shows an XFA
format:
<?xml version="1.0" encoding="UTF-8"?>
- <xfa:data xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
- <form1>
<SSN>354325426</SSN>
<fname>coldfusion</fname>
<num>354325426.00</num>
- <Subform1>
<SSN />
</Subform1>
</form1>
</xfa>
The result structure for a form created in Acrobat form could look something like the following example:
struct
firstName
[empty string]
lastName
[empty string]
department
[empty string]
...
...
To prefill the fields in ColdFusion, you add a cfpdfformparam tag for each of the fields directly under the cfpdfform tag:
917
Forms created in LiveCycle from the standard blank forms contain a subform called form1. The result structure of a
form created in LiveCycle could look like the following example:
struct
form1
struct
txtfirstName
[empty string]
txtlastName
[empty string]
txtdepartment
[empty string]
...
...
To prefill the fields in ColdFusion, add a cfpdfsubform tag for form1 and a cfpdfformparam tag for each of the fields
to fill directly below the cfpdfsubform tag:
<cfpdfform source="c:\forms\timesheetForm.pdf" action="populate">
<cfpdfsubform name="form1">
<cfpdfformparam name="txtfirstName" value="Harley">
<cfpdfformparam name="txtlastName" value="Davidson">
<cfpdfformparam name="txtDeptName" value="Engineering">
...
</cfpdfsubform>
</cfpdfform>
Note: In dynamic forms created in LiveCycle forms (forms saved as Dynamic PDF Form Files in LiveCycle Designer), you
have the option to mark how many times a record is repeated. Therefore, if no record exists for a subform, the subform
does not appear in the structure returned by the read action of the cfpdfform tag. You view these forms in LiveCycle
Designer to see the hierarchy.
Nesting subforms
Although Acrobat forms do not contain subforms, some contain complex field names. For example, an Acrobat form
could contain the following fields: form1.x.f1, form1.x.f2, form1.x.f3, and so on.
Because the cfpdfparam tag does not handle field names with periods in them, ColdFusion treats forms with complex
field names created in Acrobat the same way as subforms created in LiveCycle. Therefore, the result structure of an
Acrobat form with complex field names would look like the following example:
struct
form1
struct
x
struct
f1
[empty string]
f2
[empty string]
...
...
918
In ColdFusion, to prefill the fields in forms created in Acrobat, nest the field names as subforms:
<cfpdfform action="populate" source="acrobatForm.pdf">
<cfpdfsubform name="form1">
<cfpdfsubform name="x">
<cfpdfformparam name="f1" value="AGuthrie">
<cfpdfformparam name="f2" value="123">
<cfpdfformparam name="f3" value="456">
</cfpdfsubform>
</cfpdfsubform>
</cfpdfform>
Often, forms created in LiveCycle contain subforms within the form1 subform. For example, the following grant
application contains nested subforms:
struct
form1
struct
grantapplication
struct
page1
page2
struct
orgAddress
[empty string]
orgCity
[empty string]
orgState
[empty string]
...
...
struct
description
[empty string]
pageCount
[empty string]
...
...
To populate the fields in ColdFusion, map the structure by using nested cfpdfsubform tags:
<cfpdfform source="c:\grantForm.pdf" destination="c:\employeeid123.pdf" action="populate">
<cfpdfsubform name="form1">
<cfpdfsubform name="grantapplication">
<cfpdfsubform name="page1">
<cfpdfformparam name="orgAddress" value="572 Evergreen Terrace">
<cfpdfformparam name="orgCity" value="Springfield">
<cfpdfformparam name="orgState" value="Oregon">
...
</cfpdfsubform>
<cfpdfsubform name="page2">
<cfpdfformparam name="description" value="Head Start">
<cfpdfformparam name="pageCount" value="2">
...
</cfpdfsubform>
</cfpdfsubform>
</cfpdfsubform>
</cfpdfform>
Note: A PDF file can contain only one interactive form. Therefore, if a PDF file contains subforms, a Submit button
submits data for all the subforms simultaneously.
919
The contents of the cfpdfform tag start on a new page. Any text or code directly after the cfdocument tag and before
the cfpdfform tag applies to the document sections but not to the interactive PDF form in the cfpdfform tag.
The headers and footers that are part of the embedded PDF form do not apply to the rest of the PDF document, and
the headers and footers that are defined in the cfdocument tag do not apply to the interactive form. However, header
and footer information defined in the cfdocumentitem tags resumes in the sections that follow the embedded form
and account for the pages in the embedded form.
Note: The read action of the cfpdfform tag is not valid when you embed a PDF form. Also, you cannot specify a
destination in the cfpdfform tag. However, you can specify a filename in the cfdocument tag to write the PDF
document with the PDF form to an output file. If you do not specify a filename, ColdFusion displays the PDF form in the
context of the PDF document in the browser.
920
In LiveCycle Designer, the XML code for a PDF submission looks like the following example:
<submit format="pdf" target="http://localhost:8500/pdfforms/pdfreceiver.cfm"
textEncoding="UTF-16" xdpContent="pdf datasets xfdf"/>
Note: Acrobat forms are submitted in binary format, not XML format.
Note: When you extract data from a PDF submission, always specify "#PDF.content#" as the source.
You can set the form fields to a variable, as the following example shows:
<cfset empForm="#fields.form1#">
Use the populate action of the cfpdfform tag to write the output to a file. Specify "#PDF.content#" as the source. In
the following example, the unique filename is generated from a field on the PDF form:
<cfpdfform action="populate" source="#PDF.content#"
destination="timesheets\#empForm.txtsheet#.pdf" overwrite="yes"/>
An XDP file is an XML representation of a PDF file. In LiveCycle Designer, an XDP file contains the structure, data,
annotations, and other relevant data to LiveCycle forms, which renders the form at run time.
921
ColdFusion XDP files contain the XDP XML code and the PDF image. Therefore, the file size is larger than a PDF file.
Only write PDF forms to XDP files if you must incorporate them into the LiveCycle Designer workflow on a LiveCycle
server.
Writing PDF output to an XML file
ColdFusion lets you extract data from a PDF form and write the output to an XML data file. To do so, you must save
the form output as a PDF file. (The cfpdfform tag source must always be a PDF file.)
To write the output of a PDF file to an XML file, use the read action of the cfpdfform tag, as the following example
shows:
<cfpdfform action="read" source="#empForm.txtsheet#.pdf"
XMLdata="timesheets\#empForm.txtsheet#.xml"/>
To save disk space, you can delete the PDF file and maintain the XML data file. As long as you keep the blank PDF
form used as the template, you can use the populate action to regenerate the PDF file. For more information on
populating forms, see Populating a PDF form with XML data on page 915.
Note: When you extract data from an HTTP post submission, always specify the form name as the source. For example,
specify "#FORM.form1#" for a form generated from a standard template in LiveCycle.
Notice that the structure is not necessarily the same as the structure of the PDF file used as the template (before
submission). For example, the structure of a form before submission could look like the following example:
struct
form1
struct
txtDeptName
[empty string]
txtEMail
[empty string]
txtEmpID
[empty string]
txtFirstName
[empty string]
txtLastName
[empty string]
txtPhoneNum
[empty string]
After submission by using HTTP post, the resulting structure would look like the following example:
struct
FORM1
struct
922
struct
SUBFORM
struct
HEADER
struct
HTTPSUBMITBUTTON1
[empty string]
TXTDEPTNAME
Sales
TXTFIRSTNAME
Carolynn
TXTLASTNAME
Peterson
TXTPHONENUM
(617) 872-9178
TXTEMPID
TXTEMAIL
carolynp@company
Note: When data extraction using the cfpdfform tag results in more than one page, instead of returning one structure,
the extraction returns one structure per page.
The difference in structure reflects internal rules applied by Acrobat for the HTTP post submission.
To extract the data from the HTTP post submission and update a database with the information, for example, map the
database columns to the form fields, as the following code shows:
<cfquery name="updateEmpInfo" datasource="cfdocexamples">
UPDATE EMPLOYEES
SET FIRSTNAME = "#FORM1.SUBFORM.HEADER.TXTFIRSTNAME#",
LASTNAME = "#FORM1.SUBFORM.HEADER.TXTLASTNAME#",
DEPARTMENT = "#FORM1.SUBFORM.HEADER.TXTDEPTNAME#",
IM_ID = "#FORM1.SUBFORM.TXTEMAIL#",
PHONE = "#FORM1.SUBFORM.HEADER.TXTPHONENUM#"
WHERE EMP_ID = <cfqueryparam value="#FORM1.SUBFORM.TXTEMPID#">
</cfquery>
You can set a variable to create a shortcut to the field names, as the following code shows:
<cfset fields=#form1.subform.header#>
923
<h3>Employee Information</h3>
<cfoutput>
<table>
<tr>
<td>Name:</td>
<td>#fields.txtfirstname# #fields.txtlastname#</td>
</tr>
<tr>
<td>Department:</td>
<td>#fields.txtdeptname#</td>
</tr>
<tr>
<td>E-Mail:</td>
<td>#fields.txtemail#</td>
<tr>
<td>Phone:</td>
<td>#fields.txtphonenum#</td>
</tr>
<table>
</cfoutput>
924
On the first processing page, a query retrieves all of the information associated with the user name from the
cfdocexamples database. The cfpdfform tag populates an associated PDF form created in LiveCycle Designer (called
timesheetForm.pdf) with the employee name, phone number, e-mail address, and department. ColdFusion displays
the populated form in the browser, where the employee can complete the form and submit it.
<!--- The following code retrieves all of the employee information for the user name entered
on the login page. --->
<cfquery name="getEmpInfo" datasource="cfdocexamples">
SELECT * FROM EMPLOYEES
WHERE EMAIL = <cfqueryparam value="#FORM.username#">
</cfquery>
<!--The following code populates the template called "timesheetForm.pdf" with data from the query
and displays the interactive PDF form in the browser. A field in the PDF form contains the name
of the output file being written. It is a combination of the user name and the current date.
--->
<!--- Notice the use of the cfpdfsubform tag. Forms created from templates in LiveCycle
Designer include a subform called form1. Use the cfpdfsubform tag to match the structure of
the form in ColdFusion. Likewise, the field names in the cfpdfformparam tags must match the
field names in the PDF form. If the form structures and field names do not match exactly,
ColdFusion does not populate the form fields. --->
<cfpdfform source="c:\forms\timesheetForm.pdf" action="populate">
<cfpdfsubform name="form1">
<cfpdfformparam name="txtEmpName" value="#getEmpInfo.FIRSTNAME#
#getEmpInfo.LASTNAME#">
<cfpdfformparam name="txtDeptName" value="#getEmpInfo.DEPARTMENT#">
<cfpdfformparam name="txtEmail" value="#getEmpInfo.IM_ID#">
<cfpdfformparam name="txtPhoneNum" value="#getEmpInfo.PHONE#">
<cfpdfformparam name="txtManagerName" value="Randy Nielsen">
<cfpdfformparam name="txtSheet"
value="#form.username#_#DateFormat(Now())#">
</cfpdfsubform>
</cfpdfform>
When the user completes the timesheet form (by filling in the time period, projects, and hours for the week) and clicks
the Submit button, Acrobat sends the PDF file in binary format to a second ColdFusion processing page.
Note: In LiveCycle Designer, use the standard Submit button on the PDF form and specify submit as: PDF in the button
Object Properties. Also, ensure that you enter the URL to the ColdFusion processing page in the Submit to URL field.
The cfpdfform tag read action reads the PDF content into a result structure named fields. The cfpdfform tag
populate action writes the completed form to a file in the timesheets subdirectory.
925
<!--- The following code reads the PDF file submitted in binary format and generates a result
structure called fields. The cfpdfform populate action and the cfoutput tags reference the
fields in the structure. --->
<cfpdfform source="#PDF.content#" action="read" result="fields"/>
<cfset empForm="#fields.form1#">
<cfpdfform action="populate" source="#PDF.content#"
destination="timesheets\#empForm.txtsheet#.pdf" overwrite="yes"/>
<h3>Timesheet Completed</h3>
<p><cfoutput>#empForm.txtempname#</cfoutput>,</p>
<p>Thank you for submitting your timesheet for the week of
<cfoutput>#DateFormat(empForm.dtmForPeriodFrom, "long")#</cfoutput> through
<cfoutput>#DateFormat(empForm.dtmForPeriodto, "long")#</cfoutput>. Your manager,
<cfoutput>#empForm.txtManagerName#</cfoutput>, will notify you upon approval.</p>
On the first processing page, a query retrieves all of the information associated with the user name from the
cfdocexamples database. The cfpdfform tag populates an associated PDF form created in LiveCycle Designer (called
employeeInfoHTTP.pdf) with the employee name, phone number, e-mail address, and department. The form also
includes the employee ID as a hidden field. ColdFusion displays the populated form in the browser where the employee
can change personal information in the form and submit it.
926
<!--- The following code retrieves all of the employee information for the user name entered
on the form page. --->
<cfquery name="getEmpInfo" datasource="cfdocexamples">
SELECT * FROM EMPLOYEES
WHERE EMAIL = <cfqueryparam value="#FORM.username#">
</cfquery>
<!--- The following code populates the template called "employeeInfoHTTP.pdf" with data from
the query. As in the previous example, notice the use of the cfpdfsubform tag. The txtEmpID
field is a hidden field on the PDF form. --->
<cfquery name="getEmpInfo" datasource="cfdocexamples">
SELECT * FROM EMPLOYEES
WHERE EMAIL = <cfqueryparam value="#FORM.username#">
</cfquery>
<cfpdfform source="c:\forms\employeeInfoHTTP.pdf" action="populate">
<cfpdfsubform name="form1">
<cfpdfformparam name="txtFirstName" value="#getEmpInfo.FIRSTNAME#">
<cfpdfformparam name="txtLastName" value="#getEmpInfo.LASTNAME#">
<cfpdfformparam name="txtDeptName" value="#getEmpInfo.DEPARTMENT#">
<cfpdfformparam name="txtEmail" value="#getEmpInfo.IM_ID#">
<cfpdfformparam name="txtPhoneNum" value="#getEmpInfo.PHONE#">
<cfpdfformparam name="txtEmpID" value="#getEmpInfo.Emp_ID#">
</cfpdfsubform>
</cfpdfform>
When the employee updates the information in the form and clicks the HTTP post Submit button, Acrobat sends the
form data (but not the form itself) to a second ColdFusion processing page.
Note: In LiveCycle Designer, use the HTTP Submit button on the PDF form. Also, ensure that you enter the URL to the
ColdFusion processing page in the URL field of button Object Properties.
Reproduce the structure, not just the field name, when you reference form data. To determine the structure of the form
data, use the cfdump tag.
<!--- The following code reads the form data from the PDF form and uses it to update
corresponding fields in the database. --->
<cfquery name="updateEmpInfo" datasource="cfdocexamples">
UPDATE EMPLOYEES
SET FIRSTNAME = "#FORM1.SUBFORM.HEADER.TXTFIRSTNAME#",
LASTNAME = "#FORM1.SUBFORM.HEADER.TXTLASTNAME#",
DEPARTMENT = "#FORM1.SUBFORM.HEADER.TXTDEPTNAME#",
IM_ID = "#FORM1.SUBFORM.HEADER.TXTEMAIL#",
PHONE = "#FORM1.SUBFORM.HEADER.TXTPHONENUM#"
WHERE EMP_ID = <cfqueryparam value="#FORM1.SUBFORM.TXTEMPID#">
</cfquery>
<h3>Employee Information Updated</h3>
<p><cfoutput>#FORM1.SUBFORM.HEADER.TXTFIRSTNAME#</cfoutput>,</p>
<p>Thank you for updating your employee information in the employee database.</p>
927
On the processing page, a query populates an interactive PDF form from the cfdocexamples database. The interactive
PDF form is embedded in a PDF document created with the cfdocument tag. The PDF document comprises three
sections: the cfdocumentsection tags define the first and last sections of the document; the cfpdfform tag defines
the second section embedded in the PDF document. Each section starts a new page in the PDF document. The Print
button on the PDF form prints the entire document, including the pages in the sections before and after the interactive
PDF form.
<cfquery name="getEmpInfo" datasource="cfdocexamples">
SELECT * FROM EMPLOYEES
WHERE EMAIL = <cfqueryparam value="#FORM.username#">
</cfquery>
<!--- The following code creates a PDF document with headers and footers.
--->
<cfdocument format="pdf">
<cfdocumentitem type="header">
<font size="-1" align="center"><i>Nondisclosure Agreement</i></font>
</cfdocumentitem>
<cfdocumentitem type="footer">
<font size="-1"><i>Page <cfoutput>#cfdocument.currentpagenumber#
of#cfdocument.totalpagecount#</cfoutput></i></font>
</cfdocumentitem>
<!--- The following code creates the first section in the PDF document. --->
<cfdocumentsection>
<h3>Employee Nondisclosure Agreement</h3>
<p>Please verify the information in the enclosed form. Make any of the necessary changes
in the online form and click the <b>Print</b> button. Sign and date the last page. Staple
the pages together and return the completed form to your manager.</p>
</cfdocumentsection>
<!--- The following code embeds an interactive PDF form within the PDF document with fields
populated by the database query. The cfpdpfform tag automatically creates a section in
the PDF document. Do not embed the cfpdfform within cfdocumentsection tags. --->
<cfpdfform action="populate" source="c:\forms\embed.pdf">
<cfpdfsubform name="form1">
<cfpdfformparam name="txtEmpName"
928
value="#getEmpInfo.FIRSTNAME# #getEmpInfo.LASTNAME#">
<cfpdfformparam name="txtDeptName" value="#getEmpInfo.DEPARTMENT#">
<cfpdfformparam name="txtEmail" value="#getEmpInfo.IM_ID#">
<cfpdfformparam name="txtPhoneNum" value="#getEmpInfo.PHONE#">
<cfpdfformparam name="txtManagerName" value="Randy Nielsen">
</cfpdfsubform>
</cfpdfform>
<!--- The following code creates the last document section. Page numbering resumes in this
section. --->
<cfdocumentsection>
<p>I, <cfoutput>#getEmpInfo.FIRSTNAME# #getEmpInfo.LASTNAME#</cfoutput>, hereby attest
that the information in this document is accurate and complete.</p>
<br/><br/>
<table border="0" cellpadding="20">
<tr><td width="300">
<hr/>
<p><i>Signature</i></p></td>
<td width="150">
<hr/>
<p><i>Today's Date</i></p></td></tr>
</table>
</cfdocumentsection>
</cfdocument>
929
930
Description
addWatermark
deletePages
addheader
addfooter
removeheaderfooter
optimize
Reduces the quality of PDF documents by image downsampling and removing unused objects.
extracttext
Extracts text from the specified pages or the entire PDF documents
extractimage
Extracts images from the specified pages or the entire PDF document
transform
getInfo
Extracts information associated with the PDF document, such as the author, title, and creation date.
merge
Assembles PDF documents or pages from PDF source files into one output file.
processddx
Extends the cfpdf tag by providing a subset of Adobe LiveCycle Assembler functionality. This action is the
default.
protect
read
removeWatermark
setInfo
Sets the Title, Subject, Author, and Keywords for a PDF document,
thumbnail
write
Writes PDF output to a file. Also use to flatten forms created in Acrobat and linearize documents.
Note: You cannot use the cfpdf tag to create a PDF document from scratch. To create a PDF document from HTML
content, use the cfdocument tag. Also, you can use Report Builder to generate a report as a PDF document. Instead of
writing a PDF document to file, you can specify a PDF variable generated as the source for the cfpdf tag.
All but one of the cfpdf tag actions provide shortcuts to common tasks; for example, with one line of code, you can
add a watermark image to one or more pages in an output file, merge all the PDF documents in a directory into a single
output file, or password-protect a PDF document. ColdFusion provides two ways to extend the functionality of the
cfpdf tag: the cfpdfparam tag and the processddx action.
You use the cfpdfparam tag only with the merge action of the cfpdf tag. The cfpdfparam tag gives you more control
over which files are included in the output file; for example you can merge pages from multiple files in different
directories.
931
The processddx action extends the cfpdf tag by providing a subset of Adobe LiveCycle Assembler functionality. You
use the processddx action to process Document Description XML (DDX) instructions explained in Using DDX to
perform advanced tasks on page 943. Using DDX instructions requires more coding, but it lets you perform complex
tasks, such as generating a table of contents and adding automatic page numbers.
Also, ColdFusion provides three functions for PDF file, DDX file, and PDF variable verification:
Function
Description
IsDDX
Determines whether a DDX file, path, and instructions are not null and are valid. Also verifies that ColdFusion
supports the schema used for the DDX instructions.
IsPDFFile
Determines whether a PDF source file, path, and version are valid and supported on the server running
ColdFusion. Also verifies whether a PDF file is corrupted.
IsPDFObject
Determines whether a PDF object stored in memory is valid. Also verifies the contents of PDF variables
generated by the cfdocument and cfpdf tags.
The following table describes a few document assembly tasks that you can perform with ColdFusion:
Task
Action
elements.
Add headers and footers to a PDF document
elements
or
cfpdf action="addheader" and cfpdf action="addfooter"
elements
cfpdf action="addWatermark" and cfpdf
action="removeWatermark"
cfpdf action="protect"
newOwnerPassword="xxxxx"permissions="comma-separated list"
cfpdf action="deletePages"
Flatten (remove interactivity from) forms created in Acrobat cfpdf action="write" flatten="yes"
Generate thumbnail images from PDF document pages
Merge pages and page ranges from multiple documents in cfpdf action="merge" with multiple cfpdfparam tags
different locations into one PDF document
Merge PDF documents in a directory into one PDF
document
932
Task
Action
element
Create different versions of a PDF document
By default, ColdFusion centers the image on the page, sets the opacity of the image to 3 out of 10 (opaque), and displays
the image in the background of each page in the output file. In the following example, ColdFusion displays the
watermark in the foreground, offset 100 pixels from the left margin of the page and 100 pixels from the bottom margin
of the page. Because the opacity is set to 1, the image does not obscure the page content.
<cfpdf action="addWatermark" source="artBook.pdf"
image="../cfdocs/images/artgallery/raquel05.jpg" destination="output.pdf"
overwrite="yes" foreground="yes" opacity=1 showOnPrint="no" position="100,100">
For a complete list of attributes and settings, see the cfpdf tag in the CFML Reference.
With the ColdFusion 9 release, the addWatermark action now supports the rgb and argb formats also. The following
example shows that if you set the parameters for a new image to rgb or argb and then use the cfpdf
action=addwatermark, ColdFusion allows this action:
<!---setting the argb format for myImage--->
<cfset myImage = ImageNew("",200,200,"argb","gray")>
<!---adding watermark for myImage--->
<cfpdf action="addwatermark" rotation="45" foreground="true" image="#myImage#"
source="RemoveArts.pdf" destination="dest.pdf" overwrite="yes">
933
The processing page uses the image selected from the form as the watermark for a PDF file:
<!--- ColdFusion applies the image selected from the form as the watermark in a PDF document
by using the input variable form.art. --->
<cfpdf action="addwatermark" source="check.pdf" image="#form.art#" destination="output.pdf"
foreground="yes" overwrite="true">
<p>The watermark has been added to your personalized checks.</p>
934
<!--- Create a query to extract artwork from the cfartgallery database. --->
<cfquery name="artwork" datasource="cfartgallery">
SELECT ARTID, ARTNAME, LARGEIMAGE
FROM ART
ORDER BY ARTNAME
</cfquery>
<!--- Create a form that lists the artwork titles generated by the query. Set the value to
LARGEIMAGE so that the image file is passed to the processing page. --->
<cfform action="addWatermarkB.cfm" method="post">
<p>Please choose a title:</p>
<cfselect name="art" query="artwork" display="ARTNAME" value="LARGEIMAGE" required="yes"
multiple="no" size="8">
</cfselect>
<br/>
<cfinput type="submit" name="submit" value="OK">
</cfform>
The action page generates a ColdFusion image from the selected file by using the cfimage tag. The ImageScaleToFit
function resizes the image and applies the bicubic interpolation method to improve the resolution. To use the
manipulated image as a watermark, specify the image variable, as the following example shows:
<!--- Verify that an image file exists and is in a valid format. --->
<cfif IsImageFile("../cfdocs/images/artgallery/#form.art#")>
<!--- Use the cfimage tag to create a ColdFusion image from the file chosen from the list. --->
<cfimage source="../cfdocs/images/artgallery/#form.art#" action="read" name="myWatermark">
<!--- Use the ImageScaleToFit function to resize the image by using the bicubic interpolation
method for better resolution. --->
<cfset ImageScaleToFit(myWatermark,450,450,"bicubic")>
<!--- Use the ColdFusion image variable as the watermark in a PDF document. --->
<cfpdf action="addWatermark" source="title.pdf" image="#myWatermark#"
destination="watermarkTitle.pdf" overwrite="yes">
<cfelse>
<p>I'm sorry, no image exists for that title. Please click the Back button and try
again.</p>
</cfif>
For more information on ColdFusion images, see Creating and Manipulating ColdFusion Images on page 959.
Creating a text image and using it as a watermark
You can use the ImageDrawText function to create a text image in ColdFusion and apply the image as a watermark,
as the following example shows:
935
For more information on ColdFusion images, see Creating and Manipulating ColdFusion Images on page 959. For
an example of using DDX elements to create a text-string watermark, see Adding text-string watermarks on
page 949.
Using a PDF page as a watermark
Use the copyFrom attribute to create a watermark from the first page of a PDF file and apply it to another PDF
document. In the following example, ColdFusion creates a watermark from the first page of image.PDF, applies the
watermark to the second page of artBook.pdf, and writes the output to a new file called output.pdf:
<cfpdf action="addWatermark" copyFrom="image.pdf" source="artBook.pdf" pages="2"
destination="output.pdf" overwrite="yes">
In this example, image.pdf appears in the background of the second page of artBook.pdf. ColdFusion does not change
the size of the watermark image to fit the page. The page used as a watermark can contain text, graphics, or both.
Removing watermarks
Use the removeWatermark action to remove a watermark from one or more pages in a PDF document. The following
example shows how to remove a watermark from the entire PDF document and write the document to a new output file:
<cfpdf action="removeWatermark" source="artBook.pdf" destination="noWatermark.pdf">
The following example shows how to remove a watermark from the first two pages of a PDF document and overwrite
the source document:
<cfpdf action="removeWatermark" source="artBook.pdf" destination="artBook.pdf"
overwrite="yes" pages="1-2">
Because the source and the destination are the same and the overwrite attribute is set to yes, ColdFusion overwrites
the source file with the output file.
936
To discard unused objects such as comments, JavaScripts, attachments, bookmarks, and metadata from your PDF
document using the following attributes with optimize action:
<cfpdf action = "optimize"
noJavaScript
noThumbnails
noBookmarks
noComments
noMetadata
noFileAttachments
noLinks
nofonts>
source="./inputFiles/Source.pdf" destination="./outputFiles/Output.pdf"
Specify the source where the PDF document is located and the destination where the new PDF document with the
header and footer will be saved.
You can also specify an image or text that you need to insert in the footer along with various other attributes such as
align, bottommargin, leftmargin, numberformat, and opacity.
To remove header and footer from a PDF document, use the removeheaderfooter action, as shown in the following
snippet:
937
Use this action to remove the header and footer from a PDF document or from specified pages in a document.
The extractimage action extracts all images from the specified page number in a PDF document, as shown in the
following code snippet:
<cfpdf action = "extractimage" source = "../myBook.pdf" pages = "1-200" destination =
"..\mybookimages" imageprefix = "mybook">
The images are extracted and saved in the directory that you specify in the destination attribute. You can specify a
prefix for the images (imageprefix) being extracted, otherwise the system prefixes the image name similar to cf+page
number. To save the images in a specific format, use the format attribute.
938
To password-protect a document, set the user password. A user password controls the ability to open a document. If
you set a user password for a document, any person attempting to open the file is prompted to enter a password. The
following example sets the user password for a document:
<cfpdf action="protect" newUserPassword="openSesame" source="timesheet.pdf"
destination="myTimesheet.pdf">
In the previous example, no restrictions apply to the PDF document after the user enters the correct password. To
restrict usage and password-protect a document, add a user password and an owner password. Use the owner
password to set the permissions, as the following example shows:
<cfpdf action="protect" newUserPassword="openSesame" newOwnerPassword="topSecret"
source="timesheet.pdf" destination="myTimesheet.pdf" overwrite="yes"
permissions="AllowPrinting>
In the previous example, a person who enters the user password (openSesame) can print the document only. A person
who enters the owner password (topSecret) is considered the owner of the document, has full access to the file, and
can change the user permissions for that file.
Setting permissions on a PDF document
To set permissions on a PDF document, specify a newOwnerPassword. Conversely, you cannot set the
newOwnerPassword without also setting the permissions attribute. Only an owner can change permissions or add
passwords. For a list of permissions that an owner can set for PDF documents, see cfpdf in the CFML Reference.
Except for all or none, owners can specify a comma-separated list of permissions on a document, as the following
example shows:
<cfpdf action="protect" permissions="AllowinPrinting,AllowDegradedPrinting,AllowSecure"
source="timesheet.pdf" newOwnerPassword="private" newUserPassword="openSesame"
destination="myTimesheet.pdf">
In this example, a user must enter the password openSesame before opening the PDF form. All users can print the
document at any resolution, but only the owner can modify the document or change the permissions.
Encrypting PDF files
When you specify the protect action for a PDF file, ColdFusion encrypts the file with the RC4 128-bit algorithm by
default. Depending on the version of Acrobat running on the ColdFusion server, you can set the encryption to protect
the document contents and prevent search engines from accessing the PDF file metadata.
You can change the encryption algorithm by using the encrypt attribute. For a list of supported encryption
algorithms, see cfpdf in the CFML Reference.
The following example changes the password encryption algorithm to RC4 40-bit encryption:
<cfpdf action="protect" source="confidential.pdf" destination="confidential.pdf"
overwrite="yes" newOwnerPassword="paSSword1" newUserPassword="openSesame"
encrypt="RC4_40">
To prevent ColdFusion from encrypting the PDF document, set the encryption algorithm to none, as the following
example shows:
<cfpdf action="protect" source="confidential.pdf" encrypt="none" destination="public.pdf">
To decrypt a file, provide the owner or user password and write the output to another file. The following code decrypts
the confidential.pdf file and writes it to a new file called myDocument.pdf:
939
When you use the setInfo action, ColdFusion overwrites any existing information for that key-value pair. In the
previous example, if the pc535.pdf document contained a keyword of tax reference, ColdFusion overwrites that
keyword with Sole Proprietor, Partnership, S Corporation.
To retrieve all of the information associated with the tax file, use the cfdump tag with the getInfo action, as the
following example shows:
<cfpdf action="getInfo" source="taxes\p535.pdf" name="taxInfo">
<cfdump var="#taxInfo#">
To retrieve just the keywords for the PDF document, use this code:
<cfpdf action="getInfo" source="taxes\p535.pdf" name="taxInfo">
<cfoutput>#taxInfo.keywords#</cfoutput>
Merge the contents of a PDF variable generated by the cfdocument tag or a cfpdf tag
940
By default, ColdFusion merges the source files in descending order by timestamp. You can control the order in which
the PDF files are added to the book by setting the order and ascending attributes. The following code merges the files
in ascending order according to the timestamp on the files:
<cfpdf action="merge" directory="c:/BookFiles" destination="myBook.pdf" order="name"
ascending="yes" overwrite="yes">
By default, ColdFusion continues the merge process even if it encounters a file that is not a valid PDF document in the
specified directory. To override this setting, set the stopOnError attribute to yes, as the following example shows:
<cfpdf action="merge" directory="c:/BookFiles" destination="myBook.pdf" order="time"
ascending="yes" overwrite="yes" stopOnError="yes">
You can merge a comma-separated list of PDF files. To do this merge, specify the absolute path for each file, as the
following example shows:
<cfpdf action="merge"
source="c:\coldfusion\wwwroot\lion\Chap1.pdf,c:\coldfusion\wwwroot\lion\Chap2.pdf"
destination="twoChaps.pdf" overwrite="yes">
For more control over which files are added to the merged document, use the cfpdfparam tag with the cfpdf tag. The
cfpdfparam tag merges documents or pages from documents located in different directories into a single output file.
When you use the cfpdfparam tag, the PDF files are added to the output file in the order they appear in the code. In
the following example, the cover, title, and copyright pages are followed by the first five pages of the introduction, then
all of the pages in Chapter 1, and then the first page followed by pages 8095 in Chapter 2:
<!--- Use the cfdocument tag to create PDF content and write the output to a variable called
coverPage.--->
<cfdocument format="PDF" name="coverPage">
<html>
<body>
<h1>Cover page</h1>
<p>Please review the enclosed document for technical accuracy and completeness.</p>
</body>
</html>
</cfdocument>
<!--- Use the cfpdf tag to merge the cover page generated in ColdFusion with pages from PDF
files in different locations. --->
<cfpdf action="merge" destination="myBook.pdf" overwrite="yes" keepBookmark="yes">
<cfpdfparam source="coverPage">
<cfpdfparam source="title.pdf">
<cfpdfparam source="e:\legal\copyright.pdf">
<cfpdfparam source="boilerplate\intro.pdf" pages="1-5">
<cfpdfparam source="bookfiles\chap1.pdf">
<cfpdfparam source="bookfiles\chap2.pdf" pages="1,80-95">
</cfpdf>
Because the keepbookmark attribute is set to yes, ColdFusion retains the bookmarks from the source documents in
the output file.
Note: You cannot use the cfpdf tag to create bookmarks in a PDF document.
941
Note: If you flatten a prefilled form created in Acrobat, ColdFusion flattens the form and removes the data from the form
fields. When you specify a form created in Acrobat as a source file for merge action of the cfpdf tag, ColdFusion
automatically flattens the form and removes data from the form fields, if the fields are filled in. ColdFusion does not
support flattening forms created in LiveCycle.
For example, assume that the source file in the following example has 100 pages:
<cfpdf action="thumbnail" source="myBook.pdf">
ColdFusion generates the following files and stores them in the thumbnails directory:
942
myBook_page_1.jpg
myBook_page_2.jpg
myBook_page_3.jpg
...
myBook_page_100.jpg
If you specify a destination, ColdFusion does not create the thumbnails directory and stores the files in the specified
directory instead. The following code generates a thumbnail image called myBook_page_1.jpg from the first page of
myBook.pdf and stores it in a directory called images, which is relative to the CFM page:
<cfpdf action="thumbnail" source="myBook.pdf" pages="1" destination="images">
You change the prefix for the thumbnail filename and the change image file format to PNG or TIFF by specifying the
imagePrefix and format attributes. The following code generates a file called TOC_page_2.PNG from the second
page of myBook.pdf:
<cfpdf action="thumbnail" source="myBook.pdf" pages="2" imagePrefix="TOC" format="PNG"
destination="images">
The following code generates thumbnails from a range of pages and changes the image background to transparent (the
default is opaque):
<cfpdf action="thumbnail" source="myBook.pdf" pages="1-10,15,8-16,59" transparent="yes"
destination="\myBook\subset" imagePrefix="abridged">
For an example of how to generate thumbnail images and link them to pages in the source PDF document, see the cfpdf
tag in the CFML Reference.
ColdFusion 9 release has introduced some new attributes for the thumbnail action:
hires: You can set this attribute to true to extract high resolution images from the page. If a document contains
high resolution images and you want to retain the resolution of the images, then this attribute is useful.
For example:
<cfpdf action="thumbnail" source="./WORK/myBook.pdf" destination="./WORK/Testing_CFPDF"
overwrite="true" hires="yes">
overridepage: If you set this attribute to true, the thumbnail generated does not adhere to the PDF page size, but
to the image size that is present in that page. If the image is not present, the size is set to the maximum size of the page.
compresstiffs: Use this attribute to compress the size of the thumbnail images. As the name of the attribute
maxscale : Use this attribute to specify an integer value for the maximum scale of the thumbnail images.
maxlength: Use this attribute to specify an integer value of the maximum length of the thumbnail images.
maxbreadth: Use this attribute to specify an integer value of the maximum width of the thumbnail.
The following example illustrates the use of maxscale, maxlength, and maxbreadth:
<cfpdf action="thumbnail" source="./WORK/myBook.pdf" destination="./WORK/Testing_CFPDF"
overwrite="true" format="jpg" maxscale="3" maxlength="300" maxbreadth="200" hires="yes"
scale="100">
Note: Typically, the value of the scale attribute is set to 100 when using the maxscale attribute.
943
In ColdFusion, you verify the source DDX file with the IsDDX function:
944
<!--- The following code verifies that the DDX file exists and the DDX instructions are
valid. --->
<cfif IsDDX("merge.ddx")>
To implement the DDX instructions in ColdFusion, you create two structures: an input structure that maps the DDX
input instructions to the PDF source files, and an output structure that maps the DDX output instructions to a PDF
output file,
The following code maps two files called Chap1.pdf and Chap2.pdf to the Doc1 and Doc2 sources that you defined in
the DDX file:
<!--- This code creates a structure for the input files. --->
<cfset inputStruct=StructNew()>
<cfset inputStruct.Doc1="Chap1.pdf">
<cfset inputStruct.Doc2="Chap2.pdf">
The following code maps the output file called twoChaps.pdf to the Out1 result instruction that you defined in the
DDX file:
<!--- This code creates a structure for the output file. --->
<cfset outputStruct=StructNew()>
<cfset outputStruct.Out1="twoChaps.pdf">
To process the DDX instructions, you use the processddx action of the cfpdf tag, in which you reference the DDX
file, the input structure, and the output structure, as the following example shows:
<cfpdf action="processddx" ddxfile="merge.ddx" inputfiles="#inputStruct#"
outputfiles="#outputStruct#" name="myBook">
The name attribute creates a variable that you can use to test the success or failure of the action. If the action is
successful, ColdFusion generates an output file with the name and location specified in the output structure. The
following code returns a structure that displays a success, reason for failure, or failure message (if the reason is
unknown) for each output file, depending on the result:
<cfdump var="#myBook#">
The previous example performs the same task as the merge action in ColdFusion, as the following example shows:
<cfpdf action="merge" destination="twoChaps.pdf" overwrite="yes">
<cfpdfparam source="Chap1.pdf">
<cfpdfparam source="Chap2.pdf">
</cfpdf>
</cfif>
In this situation, it makes more sense to use the merge action because it is easier. DDX is useful when you have to
perform tasks that you cant perform with other actions in the cfpdf tag, or you require more control over specific
elements.
945
The TableOfContents element generates a table of contents from the PDF source elements that follow it. Order is
important: in the previous example, the table of contents appears on a separate page after the Title and before Doc 1
and Doc 2. The table of contents contains entries from Doc 1 and 2, but not from the title page, because the title page
precedes the table of contents in the order of instructions.
You do not reference the TableOfContents element on the corresponding ColdFusion page, as the following example
shows:
<!--- The following code verifies that the DDX file exists and the DDX instructions are
valid. --->
<cfif IsDDX("makeBook.ddx")>
<!--- This code creates a structure for the input files. --->
<cfset inputStruct=StructNew()>
<cfset inputStruct.Title="Title.pdf">
<cfset inputStruct.Doc1="Chap1.pdf">
<cfset inputStruct.Doc2="Chap2.pdf">
<!--- This code creates a structure for the output file. --->
<cfset outputStruct=StructNew()>
<cfset outputStruct.Out1="Book.pdf">
<!--- This code processes the DDX instructions and generates the book. --->
<cfpdf action="processddx" ddxfile="makeBook.ddx" inputfiles="#inputStruct#"
outputfiles="#outputStruct#" name="myBook">
</cfif>
ColdFusion generates a table of contents from the DDX instructions and inserts it in the PDF document in the location
that you provided in the DDX file. By default, the table of contents contains active links to the top-level bookmarks in
the merged PDF document.
You can change the default TableOfContents settings in the DDX file, as the following example shows:
<TableOfContents maxBookmarkLevel="infinite" bookmarkTitle="Table of Contents"
includeInTOC="false"/>
Use the maxBookmarkLevel attribute to specify the level of bookmarks included on the table of contents page. Valid values
are infinite or an integer. Use the bookmarkTitle attribute to add a bookmark to the table of contents page in the
output file. The includeInTOC attribute specifies whether the bookmark title is included on the table of contents page.
Note: You cannot specify keywords as the source for DDX. For example, if you specify <PDF source = Title/> and then
add the <_BookmarkTitle/> tag in the DDX file, ColdFusion throws an exception. This is because, the _BookmarkTitle
tag is converted to TITLE and DDX is case-sensititve.
For more information on the TableOfContents element, see the Adobe LiveCycle Assembler Document Description
XML Reference.
946
In this example, the Header and Footer elements apply only to Doc2 because they are contained within that PDF
source start and end tags; they do not apply to the table of contents or to the title page, which precede the Header and
Footer elements.
The first page of the output file is numbered Page 1 of n, and so on.
For more information on built-in keys, see the Adobe LiveCycle Assembler Document Description XML Reference.
947
To apply the style profile, specify the StyleProfile name by using the styleReference attribute of the Header
element, as the following example shows:
<?xml version="1.0" encoding="UTF-8"?>
<DDX xmlns="http://ns.adobe.com/DDX/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
<PDF result="Out1">
<PDF source="Title"/>
<TableOfContents>
<Header styleReference="TOCheaderStyle"/>
</TableOfContents>
<PDF source="Doc1"/>
<PDF source="Doc2"/>
<PDF source="Doc3"/>
<PDF source="Doc4"/>
</PDF>
<StyleProfile name="TOCheaderStyle">
<Header>
<Center>
<StyledText>
<p> color="red" font-weight="bold" font="Arial">Table of Contents</p>
</StyledText>
</Center>
</Header>
</StyleProfile>
</DDX>
948
For a complete example, see Using DDX instructions to create a book on page 954.
In this example, the first time the PDF document is displayed in Acrobat Reader, the document is opened to page two
and the bookmark panel is displayed. The magnification of the document is adjusted to fit the page.
949
For more information on IntialViewProfile settings, see the Adobe LiveCycle Assembler Document Description
XML Reference.
The following example shows how to add different backgrounds on alternating pages. The verticalAnchor attribute
displays the background text at the top of the page:
<?xml version="1.0" encoding="UTF-8"?>
<DDX xmlns="http://ns.adobe.com/DDX/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
<PDF result="Out1">
<Background alternation="EvenPages" verticalAnchor="Top">
<StyledText><p font-size="20pt" font-weight="bold" color="gray"
font="Arial">DRAFT</p></StyledText>
</Background>
<Background alternation="OddPages" verticalAnchor="Top">
<StyledText><p font-size="20pt" font-weight="bold" color="gray"
font="Arial"><i>Beta 1</i></p></StyledText>
</Background>
...
</PDF>
</DDX>
Instead of applying watermarks to the entire output file, you can apply them to individual source files. The following
example applies a different background to the first three chapters of a book. The fourth chapter has no background:
950
For more information on using DDX instructions to create watermarks, see the Adobe LiveCycle Assembler Document
Description XML Reference.
The following code shows the CFM page that calls the DDX file. Instead of writing the output to a PDF file, you specify
an XML file for the output:
951
<cfif IsDDX("documentText.ddx">
<cfset ddxfile = ExpandPath("documentText.ddx")>
<cfset sourcefile1 = ExpandPath("book1.pdf")>
<cfset destinationfile = ExpandPath("textDoc.xml")>
<cffile action="read" variable="myVar" file="#ddxfile#"/>
<cfset inputStruct=StructNew()>
<cfset inputStruct.Doc1="#sourcefile1#">
<cfset outputStruct=StructNew()>
<cfset outputStruct.Out1="#destinationfile#">
<cfpdf action="processddx" ddxfile="#myVar#" inputfiles="#inputStruct#"
outputfiles="#outputStruct#" name="ddxVar">
<!--- Use the cfdump tag to verify that the PDF files processed successfully. --->
<cfdump var="#ddxVar#">
</cfif>
The XML file conforms to a schema specified in doctext.xsd. For more information, see
http://ns.adobe.com/DDX/DocText/1.0
When you specify more than one source document, ColdFusion aggregates the pages into one file. The following
example shows the DDX code for combining a subset of pages from two documents into one output file:
<?xml version="1.0" encoding="UTF-8"?>
<DDX xmlns="http://ns.adobe.com/DDX/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
<DocumentText result="Out1">
<PDF source="doc1" pages="1-10"/>
<PDF source="doc2" pages="3-5"/>
</DocumentText>
</DDX>
Form data can now be populated in a PDF document using the populate action. The new fdf attribute with populate
allows you use the FDF format internally. Following code snippet illustrates this feature:
952
Application examples
The following examples show you how to use the cfpdf tag to perform PDF document operations in simple
applications.
Use the getInfo action to perform a keyword search on PDF files in a directory.
Create a comma-separated list of files that match the search criteria.
Use the merge action to merge the PDF documents in the comma-separated list into an output file.
The first CFM page creates a form for selecting the tax documents based on the business type:
953
The action page loops through the files in the taxes subdirectory and uses the getInfo action to retrieve the keywords
for each file. If the PDF file contains the business type keyword (Sole Proprietor, Partnership, or S Corporation),
ColdFusion adds the absolute path of the file to a comma-separated list. The merge action assembles the files in the list
into an output PDF file:
<!--- Create a variable for the business type selected from the form. --->
<cfset bizType=#form.businessType#>
<!--- Create a variable for the path of the current directory. --->
<cfset thisPath=ExpandPath(".")>
<!--- List the files in the taxes subdirectory. --->
<cfdirectory action="list" directory="#thisPath#\taxes" name="filelist">
<!--- The following code loops through the files in the taxes subdirectory. The getInfo
action to retrieves the keywords for each file and determines whether the business type
matches one of the keywords in the file. If the file contains the business type keyword,
ColdFusion adds the file to a comma-separated list. --->
<cfset tempPath="">
<cfloop query="filelist">
<cfset fPath="#thisPath#\taxes\#filelist.name#">
<cfpdf action="GetInfo" source="#fPath#" name="kInfo"></cfpdf>
<cfif #kInfo.keywords# contains "#bizType#">
<cfset tempPath=#tempPath# & #fPath# & ",">
</cfif>
</cfloop>
<!--- Merge the files in the comma-separated list into a PDF output file called "taxMerge.pdf".
--->
<cfpdf action="merge" source="#tempPath#" destination="taxMerge.pdf" overwrite="yes"/>
<h3>Assembled Tax Document</h3>
<p>Click the following link to view your assembled tax document:</p>
<a href="http://localhost:8500/Lion/taxmerge.pdf">
<p>Your Assembled Tax Document</a></p>
954
955
</Right>
</Footer>
</StyleProfile>
<StyleProfile name="FooterStyle">
<Footer>
<Left>
<StyledText>
<p font-size="9pt"><i>CFML Reference</i></p>
</StyledText>
</Left>
<Right>
<StyledText>
<p font-size="9pt">Page <_PageNumber/> of <_LastPageNumber/></p>
</StyledText>
</Right>
</Footer>
</StyleProfile>
</DDX>
The following code shows the ColdFusion page that processes the DDX instructions:
<cfif IsDDX("Book.ddx")>
<cfset inputStruct=StructNew()>
<cfset inputStruct.Doc0="Title.pdf">
<cfset inputStruct.Doc1="Chap1.pdf">
<cfset inputStruct.Doc2="Chap2.pdf">
<cfset inputStruct.Doc3="Chap3.pdf">
<cfset inputStruct.Doc4="Chap4.pdf">
<cfset outputStruct=StructNew()>
<cfset outputStruct.Out1="myBook.pdf">
<cfpdf action="processddx" ddxfile="book.ddx" inputfiles="#inputStruct#"
outputfiles="#outputStruct#" name="ddxVar">
<cfoutput>#ddxVar.Out1#</cfoutput>
</cfif>
Use the cfpdfform and cfpdfformparam tags to populate a form created in Acrobat.
Use the cfpdfform tag to write the output of a PDF post submission to a file.
Use the cfpdfprocessddx action to apply a text-string watermark to the completed form.
Note: This example uses the cfdocexamples database and the 1040 and 1040ez Federal tax forms. A valid user name is
cpeterson. To download the 1040 and 1040ez IRS tax forms used in this example, go to the IRS website. Open the forms
in Acrobat (not LiveCycle Designer) and add a submit button that points to the URL for the ColdFusion processing page.
Also, add a hidden field with a variable that contains a unique filename used for the completed tax form.
The first ColdFusion page creates a login form that prompts for the user name and Social Security Number:
956
<!--- The following code creates a simple form for entering a user name and password. The
code does not include password verification. --->
<h3>Tax Login Form</h3>
<p>Please enter your user name and your social security number.</p>
<cfform name="loginform" action="TaxFile2.cfm" method="post">
<table>
<tr>
<td>User name:</td>
<td><cfinput type="text" name="username" required="yes"
message="A user name is required."></td>
</tr>
<tr>
<td>SSN#:</td>
<td><cfinput type="text" name="SS1" maxLength="3" size="3"
required="yes" mask="999"> <cfinput type="text" name="SS2" maxLength="2" size="2" required="yes"
mask="99"> <cfinput type="text" name="SS3" maxLength="4" size="4" required="yes"
mask="9999"></td>
</tr>
</table>
<br/>
<cfinput type="submit" name="submit" value="Submit">
</cfform>
The second ColdFusion page retrieves the user information from the cfdocexamples database. Also, it creates a popup menu with a list of available tax forms:
957
<!--- The following code retrieves all of the employee information for the
user name entered on the login page. --->
<cfquery name="getEmpInfo" datasource="cfdocexamples">
SELECT * FROM EMPLOYEES
WHERE EMAIL = <cfqueryparam value="#FORM.username#">
</cfquery>
<h3>Choose a tax form</h3>
<p>Hello <cfoutput>#getEmpInfo.firstname#</cfoutput>,</p>
<p>Please choose a tax form from the list:</p>
<!--- Create a pop-up menu with a list of tax forms. --->
<cfset thisPath=ExpandPath(".")>
<!--- Create a variable called filerID that is a combination of the username and the last
three digits of the Social Security number. --->
<cfset filerID="#form.username#_#form.SS3#">
<cfdirectory action="list" name="taxForms" directory="#thisPath#/taxforms">
<cfform name="taxList" method="post" action="TaxFile3.cfm">
<cfselect query="taxForms" value="name" size="10" required="yes" multiple="no"
name="myTaxForm"/>
<br/><br/>
<cfinput type="Submit" name="OK" label="OK">
<!--- Use hidden fields to pass the first name, last name, and the three parts of
the SSN# to the tax form. Also, create a hidden field for the filerID variable. --->
<cfinput type="hidden" name="FirstName" value="#getEmpInfo.FirstName#">
<cfinput type="hidden" name="LastName" value="#getEmpInfo.LastName#">
<cfinput type="hidden" name="Phone" value="#getEmpInfo.Phone#">
<cfinput type="hidden" name="SS1" value="#form.SS1#">
<cfinput type="hidden" name="SS2" value="#form.SS2#">
<cfinput type="hidden" name="SS3" value="#form.SS3#">
<cfinput type="hidden" name="taxFiler" value="#filerID#">
</cfform>
The third ColdFusion page uses the cfpdfform and cfpdfformparam tags to populate the tax form with the user
information. ColdFusion displays the tax prefilled tax form in the browser window where the user can complete the
rest of the form fields. When the user clicks the submit button, Acrobat sends the completed PDF form to the
ColdFusion processing page.
Note: To prefill forms, map each PDF form field name to the corresponding data element in a cfpdfformparam tag. To
view the form fields, open the form in Acrobat Professional and select Forms > Edit Forms in Acrobat. For more
information about prefilling forms, see Manipulating PDF Forms in ColdFusion on page 914.
958
<!--- The following code populates the tax form template chosen from the list with
information from the database query and the login form. Because no destination is
specified, ColdFusion displays the interactive PDF form in the browser. A hidden field
in the PDF form contains the name of the output file to write. It is a combination of
the user name and the last three numerals of the user SSN#. The submit button added to
the form created in Acrobat contains a URL to the ColdFusion processing page. --->
<cfpdfform source="taxForms/#form.myTaxForm#" action="populate">
<cfif "taxForms/#form.myTaxForm#" is "taxForms/f1040.pdf">
<cfpdfformparam name="f1_04(0)" value="#form.Firstname#">
<cfpdfformparam name="f1_05(0)" value="#form.Lastname#">
<cfpdfformparam name="f2_115(0)" value="#form.Phone#">
<cfpdfformparam name="f1_06(0)" value="#form.SS1#">
<cfpdfformparam name="f1_07(0)" value="#form.SS2#">
<cfpdfformparam name="f1_08(0)" value="#form.SS3#">
<cfpdfformparam name="filerID" value="#form.taxFiler#_1040">
<cfelseif "taxForms/#form.myTaxForm#" is "taxForms/f1040ez.pdf">
<cfpdfformparam name="f1_001(0)" value="#form.Firstname#">
<cfpdfformparam name="f1_002(0)" value="#form.Lastname#">
<cfpdfformparam name="f1_070(0)" value="#form.Phone#">
<cfpdfformparam name="f1_003(0)" value="#form.SS1#">
<cfpdfformparam name="f1_004(0)" value="#form.SS2#">
<cfpdfformparam name="f1_005(0)" value="#form.SS3#">
<cfpdfformparam name="filerID" value="#form.taxFiler#_1040ez">
</cfif>
</cfpdfform>
The fourth ColdFusion page uses the cfpdfform tag to process the PDF post submission and generate an output file.
The filename is generated from the value of the hidden field in the tax form. The processddx action of the cfpdf tag
uses the DDX instructions in the watermark.ddx file to generate a text-string watermark and apply it to the form.
The following code shows the contents of the watermark.ddx file:
<?xml version="1.0" encoding="UTF-8"?>
<DDX xmlns="http://ns.adobe.com/DDX/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ns.adobe.com/DDX/1.0/ coldfusion_ddx.xsd">
<PDF result="Out1">
<PDF source="Doc1">
<Watermark rotation="30" opacity="65%">
<StyledText><p font-size="85pt" font-weight="bold" color="gray"
font="Arial">FINAL</p></StyledText>
</Watermark>
</PDF>
</PDF>
</DDX>
<!--- The following code reads the PDF file submitted in binary format and generates a result
structure called fields. The cfpdfform populate action and the cfoutput tags reference
the fields in the structure. --->
<cfpdfform source="#PDF.content#" action="read" result="fields"/>
<cfpdfform action="populate" source="#PDF.content#"
destination="FiledForms\#fields.filerID#.pdf" overwrite="yes"/>
<!--- The following code verifies that the DDX file exists and the DDX instructions are
valid. --->
959
<cfif IsDDX("watermark.ddx")>
<!--- The following code uses the processddx action of the cfpdf tag to create a textstring watermark. --->
<!--- This code creates a structure for the input files. --->
<cfset inputStruct=StructNew()>
<cfset inputStruct.Doc1="FiledForms\#fields.filerID#.pdf">
<!--- This code creates a structure for the output file. --->
<cfset outputStruct=StructNew()>
<cfset outputStruct.Out1="FiledForms\#fields.filerID#.pdf">
<!--- This code processes the DDX instructions and applies the watermark to the form. --->
<cfpdf action="processddx" ddxfile="watermark.ddx" inputfiles="#inputStruct#"
outputfiles="#outputStruct#" name="Final">
</cfif>
<h3>Tax Form Completed</h3>
<p>Thank you for filing your tax form on line. Copy this URL to view or download your filed
tax form:</p>
<cfoutput>
<a href="http://localhost:8500/Lion/FiledForms/#fields.filerID#.pdf">
Link to your completed tax form</a>
</cfoutput>
IsImage function
IsImageFile function
Create a watermark
function
960
Task
ImageReadBase64 function
cffile tag to convert an image file to a binary object and then pass the
binary object to the ImageNew function
Description
border
captcha
convert
info
Creates a ColdFusion structure that contains information about the image, including the color model, height, width,
and source of the image.
read
Reads an image from the specified local file path or URL. If you do not specify an action explicitly, ColdFusion uses
read as the default value.
resize
rotate
write
Writes the image to a file. You can use the write action to generate lower-resolution JPEG files. Also, use the write
action to convert images to other file formats, such as PNG and GIF.
writeToBrowser
Writes one or more images directly to a browser. Use this action to test the appearance of a single image or write
multiple images to the browser without saving the images to files.
For more information, see the cfimage tag in the CFML Reference.
961
Image functions
ColdFusion provides more than 50 Image functions that expand on the functionality of the cfimage tag. You can pass
images created with the cfimage tag to Image functions or create images with the ImageNew function. The following
table groups the Image functions by category:
Category
Image functions
Manipulating images
ImageNew function
Create a ColdFusion image from BLOB data in a database. ImageNew function with the cfquery tag
Create a ColdFusion image from a binary object.
You do not have to specify the read action because it is the default action. Specify the name attribute for the read
action, which creates a variable that contains the ColdFusion image, for example, myImage.
You can pass the myImage variable to another cfimage tag or to Image functions. The following example shows how
to specify a ColdFusion image variable as the source:
<cfimage source="#myImage#" action="write" destination="test_myImage.jpg">
962
The write action writes the file to the specified destination, which can be an absolute or relative path. The following
example shows how to create a ColdFusion image from a URL and write it to a file on the local storage drive:
<cfimage source="http://www.google.com/images/logo_sm.gif" action="write"
destination="c:\images\logo_sm.gif">
As with the cfimage tag, you can specify an absolute or relative path, a URL, or another ColdFusion image as the
source. In the following example, ColdFusion reads a file from the local drive and passes it to the ImageWrite function,
which writes the image to a new file:
<cfset myImage=ImageNew("../cfdocs/images/artgallery/jeff01.jpg")>
<cfset ImageWrite(myImage,"myImageTest.png")>
Also, you can create a blank image. When using the ImageNew function, you do not specify the source to create a blank
image. However, you can specify the width and height, respectively. The following example shows how to create a
blank canvas that is 300 pixels wide and 200 pixels high:
<cfset myImage=ImageNew("",300,200)>
Optionally, you can specify the image type, as in the following example:
<cfset myImage=ImageNew("",200,300,"rgb")>
Other valid image types are argb and grayscale. You can use blank images as canvasses for drawing functions in
ColdFusion. For examples, see Creating watermarks on page 973.
Also, you can use the ImageNew function to create ColdFusion images from other sources, such as Base64 bytearrays,
file paths, and URLs. The following example creates a ColdFusion image from a JPEG file (x), and then creates another
ColdFusion image (y) from the image in memory:
<cfset x = ImageNew("c:\abc.jpg")>
<cfset y = ImageNew(x)>
For more information about the ImageNew function, see the CFML Reference.
963
<!--- Use the cffile tag to read an image file, convert it to binary format, and write the
result to a variable. --->
<cffile action = "readBinary" file = "jeff05.jpg" variable = "aBinaryObj">
<!--- Use the ImageNew function to create a ColdFusion image from the variable. --->
<cfset myImage=ImageNew(aBinaryObj)>
The following example shows how to use the ImageNew function to generate ColdFusion images from BLOB data:
<!--- Use the cfquery tag to retrieve all employee photos and employee IDs from a database. --->
<cfquery name="GetBLOBs" datasource="myBlobData">
SELECT EMLPOYEEID, PHOTO FROM Employees
</cfquery>
<!--- Use the ImageNew function to create a ColdFusion images from the BLOB data that was
retrieved from the database. --->
<cfset myImage = ImageNew(GetBLOBs.PHOTO)>
<!--- Create thumbnail versions of the images by resizing them to fit in a 100-pixel square,
while maintaining the aspect ratio of the source image. --->
<cfset ImageScaleToFit(myImage,100,100)>
<!--- Convert the images to JPEG format and save them to files in the thumbnails subdirectory,
using the employee ID as the filename. --->
<cfimage source="#myImage#" action="write"
destination="images/thumbnails/#GetBLOBs.EMPLOYEID#.jpg">
For information on converting a ColdFusion image to a BLOB, see Inserting an image as a BLOB in a database on
page 966.
964
The following examples show how to use the ImageReadBase64 function to create a ColdFusion image from a Base64
string:
<!--- This example shows how to use the ImageReadBase64 function to read a Base64 string
with headers. --->
<cfset myImage=ImageReadBase64("data:image/jpg;base64,/9j/4AAQSkZJRgABAQA..............")>
<!--- This example shows how to read a Base64 string without headers. --->
<cfset myImage=ImageReadBase64("/9j/4AAQSkZJRgABAQA..............")>
For more information on Base64 strings, see Converting an image to a Base64 string on page 966.
Copying an image
You use the ImageCopy function to copy a rectangular area of an existing image and generate a new ColdFusion image
from it. You can paste the new ColdFusion image onto another image, or write it to a file, as the following example
shows:
<!--- Use the cfimage tag to create a ColdFusion image from a JPEG file.
--->
<cfimage source="../cfdocs/images/artgallery/lori05.jpg" name="myImage">
<!--- Turn on antialiasing to improve image quality. --->
<cfset ImageSetAntialiasing(myImage)>
<!--- Copy the rectangular area specified by the coordinates (25,25,50,50) in the image to
the rectangle beginning at (75,75), and return this copied rectangle as a new ColdFusion
image. --->
<cfset dupArea = ImageCopy(myImage,25,25,50,50,75,75)>
<!--- Write the new ColdFusion image (dupArea) to a PNG file. --->
<cfimage source="#dupArea#" action="write" destination="test_myImage.png" overwrite="yes">
Duplicating an image
Another way to create a ColdFusion image is to duplicate it. Duplicating an image creates a clone, which is a copy of
an image that is independent of it: if the original image changes, those changes do not affect the clone, and the reverse.
This technique is useful if you want to create several versions of the same image. Duplicating an image can improve
processing time because you retrieve image data from a database or a file once to create the ColdFusion image. Then
you can create several clones and manipulate them in memory before writing them to files. For example, you could
create a thumbnail version, a grayscale version, and an enlarged version of an image uploaded to a server. To do so,
you use the cfimage tag or the ImageNew function to create a ColdFusion image from the uploaded file. You use the
Duplicate function to create three clones of the ColdFusion image.
965
To create a clone, you can pass a ColdFusion image variable to the Duplicate function:
<!--- Use the ImageNew function to create a ColdFusion image from a JPEG file. --->
<cfset myImage=ImageNew("../cfdocs/images/artgallery/paul01.jpg")>
<!--- Turn on antialiasing to improve image quality. --->
<cfset ImageSetAntialiasing(myImage)>
<!--- Use the Duplicate function to create three clones of the ColdFusion image. --->
<cfset cloneA=Duplicate(myImage)>
<cfset cloneB=Duplicate(myImage)>
<cfset cloneC=Duplicate(myImage)>
<!--- Create a grayscale version of the image. --->
<cfset ImageGrayscale(cloneA)>
<!--- Create a thumbnail version of the image. --->
<cfset ImageScaleToFit(cloneB,50,"")>
<!--- Create an enlarged version of the image. --->
<cfset ImageResize(cloneC,"150%","")>
<!--- Write the images to files. --->
<cfset ImageWrite(myImage,"paul01.jpg","yes")>
<cfset ImageWrite(cloneA,"paul01_bw.jpg","yes")>
<cfset ImageWrite(cloneB,"paul01_sm.jpg","yes")>
<cfset ImageWrite(cloneC,"paul01_lg.jpg","yes")>
<!--- Display the images. --->
<img src="paul01.jpg">
<img src="paul01_bw.jpg">
<img src="paul01_sm.jpg">
<img src="paul01_lg.jpg">
Also, you can use the cfimage tag and the ImageNew function to duplicate images, as the following example shows:
<!--- Use the cfimage tag to create a ColdFusion image (myImage) and make a copy of it
(myImageCopy). --->
<cfimage source="../cfdocs/images/artgallery/paul01.jpg" name="myImage">
<cfimage source="#myImage#" name="myImageCopy">
<!-- Use the ImageNew function to make a copy of myImage called myImageCopy2. --->
<cfset myImageCopy2 = ImageNew(myImage)>
Converting images
ColdFusion makes it easy to convert images from one file format to another. Also, you can convert an image file to a
binary object, BLOB data, or a Base64 string.
Similarly, you can use the ImageWrite function with the ImageNew function:
<cfset myImage=ImageNew("../cfdocs/images/artgallery/jeff01.jpg")>
<cfset ImageWrite(myImage,"jeff01.gif")>
966
ColdFusion reads and writes most standard image formats. For more information, see Supported image file formats
in the CFML Reference.
Verifying images
Use the IsImage function to test whether an image variable represents a valid ColdFusion image. This function takes
a variable name as its only parameter and returns a Boolean value.
Note: You cannot use the IsImage function to verify whether files are valid images. Instead, use the IsImageFile
function.
Also, ColdFusion provides two tags for determining which image file formats are supported on the server where the
ColdFusion application is deployed: GetReadableImageFormats and GetWriteableImageFormats. For more
information, see the CFML Reference.
967
<!--- Create a ColdFusion image named "myImage" from a file uploaded to the server. --->
<cfimage action="read" source="#fileUpload.serverFile#" name="myImage">
<!--- Determine whether the file is greater than 300 pixels in width or height. --->
<cfif ImageGetHeight(myImage) gt 300 or ImageGetWidth(myImage) gt 300>
<!--- If the file exceeds the size limits, delete it from the server. --->
<cffile action="delete" file="#fileUpload.serverDirectory#/#fileUpload.serverFile#">
<cfoutput>
<!--- Display the following message. --->
<p>
The image you uploaded was too big. It must be less than 300 pixels wide and 300 pixels
high. Your image was #imageGetWidth(myImage)# pixels wide and
#imageGetHeight(myImage)# pixels high.
</p>
</cfif>
For information about retrieving image metadata, see the ImageGetEXIFTag, ImageGetIPTCTag, and ImageInfo
functions in the CFML Reference.
You can perform the same operation by using the ImageWrite function:
<cfset myImage=ImageNew("jeff05.jpg")>
<cfset ImageWrite(myImage,"jeff05_lq.jpg","0.5")>
The border is added to the outside edge of the source image. This increases the area of the image.
To create complex borders, use the ImageAddBorder function. The following example shows how to nest borders:
968
Also, with the ImageAddBorder function, you can add a border that is an image effect. For example, you can use the
wrap parameter to create a tiled border from the source image. The wrap parameter creates a tiled border by adding
the specified number of pixels to each side of the image, as though the image were tiled.
In the following example, 20 pixels from the outside edge of the source image are tiled to create the border:
<cfset myImage=ImageNew("../cfdocs/images/artgallery/jeff03.jpg")>
<cfset ImageAddBorder(myImage,20,"","wrap")>
<cfset ImageWrite(myImage,"testMyImage.jpg")>
<img src="testMyImage.jpg"/>
For examples of other border types, see the ImageAddBorder function in the CFML Reference.
969
<!--- This example shows how to create a CAPTCHA image with the text "rEadMe" and write the
image directly to the browser. --->
<cfimage action="captcha" fontSize="25" width="162" height="75" text="rEadMe"
fonts="Verdana,Arial,Courier New,Courier">
Note: For the CAPTCHA image to display, the width value must be greater than: fontSize times the number of
characters specified in text times 1.08. In this example, the minimum width is 162.
ColdFusion 9 supports CAPTCHA images in PNG format only.
Note: If you specify the destination attribute to write CAPTCHA images to files, use unique names for the CAPTCHA
image files so that when multiple users access the CAPTCHA images, the files are not overwritten.
The following example shows how to create CAPTCHA images with a high level of text distortion.
<!--- Use the GetTickCount function to generate unique names for the CAPTCHA files. --->
<cfset tc = GetTickCount()>
<!--- Set the difficulty to "high" for a higher level of text distortion. --->
<cfimage action="captcha" fontSize="15" width="180" height="50" text="rEadMe"
destination="readme#tc#.png" difficulty="high">
For a detailed example, see Using CAPTCHA to verify membership on page 979.
The following image shows three CAPTCHA images with low, medium, and high levels of difficulty, respectively:
In the previous examples, the text is displayed in the default system font and font size. To control the appearance of
the text, you specify a collection of text attributes, as the following example shows:
<cfset
<cfset
<cfset
<cfset
<cfset
attr = StructNew()>
attr.style="bolditalic">
attr.size=20>
attr.font="verdana">
attr.underline="yes">
To apply the text attributes to the text string, include the attribute collection name in the ImageDrawText definition.
In the following examples, the "attr" text attribute collection applies the text string "Congratulations!":
970
...
<cfset ImageDrawText(myImage,"Congratulations!",10,50,attr)>
To change the color of the text, use the ImageSetDrawingColor function. This function controls the color of all
subsequent drawing objects on an image. In the following example, two lines of text, Congratulations! and
Gabriella, inherit the color magenta.
<!--- This example shows how to draw a text string on a blank image. --->
<cfset myImage=ImageNew("../cfdocs/images/artgallery/jeff01.jpg")>
<cfset ImageSetDrawingColor(myImage,"magenta")>
<cfset attr = StructNew()>
<cfset attr.style="bolditalic">
<cfset attr.size=20>
<cfset attr.font="verdana">
<cfset attr.underline="yes">
<cfset ImageDrawText(myImage,"Congratulations!",10,50,attr)>
<cfset ImageDrawText(myImage,"Gabriella",50,125,attr)>
<cfimage source="#myImage#" action="write" destination="myImage.jpg" overwrite="yes">
<img src="myImage.jpg"/>
For a list of valid named colors, see the cfimage tag in the CFML Reference.
Note: To draw a sequence of connected lines, use the ImageDrawLines function. For more information, see the CFML
Reference.
971
Drawing controls apply to all subsequent drawing functions in an image; therefore, order is important. In the following
example, the drawing stroke attributes defined in the attribute collection apply to the square and the two lines.
Similarly, the color green applies to the rectangle and the square, while the color red applies only to the two lines. You
can reset a drawing control as many times as necessary within an image to achieve the desired effect.
<!--- Create an attribute collection for the drawing stroke. --->
<cfset attr=StructNew()>
<cfset attr.width="4">
<cfset attr.endcaps="round">
<cfset attr.dashPattern=ArrayNew(1)>
<cfset dashPattern[1]=8>
<cfset dashPattern[2]=6>
<cfset attr.dashArray=dashPattern>
<cfset myImage=ImageNew("",200,200)>
<cfset ImageDrawOval(myImage,40,20,100,100)>
<!--- Set the drawing color to green for all subsequent drawing functions. --->
<cfset ImageSetDrawingColor(myImage,"green")>
<cfset ImageDrawRect(myImage,70,50,40,20,true)>
<!--- Apply the attribute collection to all subsequent shapes and lines in the image. --->
<cfset ImageSetDrawingStroke(myImage,attr)>
<cfset ImageDrawRect(myImage,40,40,100,100)>
<!--- Set the drawing color to red for all subsequent drawing functions. --->
<cfset ImageSetDrawingColor(myImage,"red")>
<cfset ImageDrawLine(myImage,130,40,100,200)>
<cfset ImageDrawLine(myImage,50,40,100,200)>
<cfimage source="#myImage#" action="write" destination="testMyImage.gif" overwrite="yes">
<img src="testMyImage.gif"/>
Resizing images
ColdFusion makes it easy to resize images. You can reduce the file size of an image by changing its dimensions, enforce
uniform sizes on images, and create thumbnail images. The following table describes the ways to resize images in
ColdFusion:
Task
Resize an image
ImageScaleToFit function
ImageResize function
972
<!--- This example shows how to specify the height and width of an image in pixels. --->
<cfimage source="../cfdocs/images/artgallery/jeff01.jpg" action="resize" width="100"
height="100" destination="jeff01_sm.jpg">
<!--- This example shows how to specify the height and width of an image as percentages. --->
<cfimage source="../cfdocs/images/artgallery/jeff02.jpg" action="resize" width="50%"
height="50%" destination="jeff02_sm.jpg">
<!--- This example shows how to specify the height of an image in pixels and its width as a
percentage. Notice that this technique can distort the image. --->
<cfimage source="../cfdocs/images/artgallery/jeff03.jpg" action="resize" width="50%"
height="100" destination="jeff03_sm.jpg" overwrite="yes">
The cfimage tag requires that you specify both the height and the width for the resize action.
The cfimage tag resize action uses the highestQuality interpolation method for the best quality image (at the cost
of performance). For faster display, use the ImageResize function or the ImageScaleToFit function.
Using the ImageResize function
The ImageResize function is like the cfimage tag resize action. To ensure that the resized image is proportional,
specify a value for the height or width and enter a blank value for the other dimension:
<!--- This example shows how to resize an image to 50% of original size and resize it
proportionately to the new width. The height value is blank. --->
<cfset myImage=ImageNew("http://www.google.com/images/logo_sm.gif")>
<cfset ImageResize(myImage,"50%","")>
<!--- Save the modified image to a file. --->
<cfimage source="#myImage#" action="write" destination="test_myImage.jpeg" overwrite="yes">
<!--- Display the source image and the resized image. --->
<img src="http://www.google.com/images/logo_sm.gif"/>
<img src="test_myImage.jpeg"/>
The ImageResize function also lets you specify the type of interpolation used to resize the image. Interpolation lets
you control the trade-off between performance and image quality. By default, the ImageResize function uses the
highestQuality interpolation method. To improve performance (at the cost of image quality), change the
interpolation method. Also, you can set the blur factor for the image. The default value is 1 (not blurred). The highest
blur factor is 10 (very blurry). The following example shows how to resize an image using the highPerformance form
of interpolation with a blur factor of 10:
<cfset myImage=ImageNew("../cfdocs/images/artgallery/aiden01.jpg")>
<cfset ImageResize(myImage,"","200%","highPerformance", 10)>
<cfimage action="writeToBrowser" source="#myImage#">
973
<!--- This example shows how to resize an image to a 100-pixel square, while maintaining the
aspect ratio of the source image. --->
<cfimage source="../cfdocs/images/artgallery/jeff05.jpg" name="myImage" action="read">
<!--- Turn on antialiasing. --->
<cfset ImageSetAntialiasing(myImage)>
<cfset ImageScaleToFit(myImage,100,100,"mediumQuality")>
<!--- Display the modified image in a browser. --->
<cfimage source="#myImage#" action="writeToBrowser">
To fit an image in a defined rectangular area, specify the width and height of the rectangle, as the following example
shows:
<!--- This example shows how to resize an image to fit in a rectangle that is 200 pixels
wide and 100 pixels high, while maintaining the aspect ratio of the source image. --->
<cfimage source="../cfdocs/images/artgallery/jeff05.jpg" name="myImage">
<!--- Turn on antialiasing. --->
<cfset ImageSetAntialiasing(myImage)>
<cfset ImageScaleToFit(myImage,200,100)>
<!--- Display the modified image in a browser. --->
<cfimage source="#myImage#" action="writeToBrowser">
In this example, the width of the resulting image is less than or equal to 200 pixels and the height of the image is less
than or equal to 100 pixels.
Also, you can specify just the height or just the width of the rectangle. To do so, specify an empty string for the
undefined dimension. The following example resizes the image so that the width is exactly 200 pixels and the height
of the image is proportional to the width:
<!--- This example shows how to resizes an image so that it is 200 pixels wide, while
maintaining the aspect ratio of the source image. The interpolation method is set to
maximize performance (which reduces image quality). --->
<cfimage source="../cfdocs/images/artgallery/jeff05.jpg" name="myImage">
<!--- Turn on antialiasing. --->
<cfset ImageSetAntialiasing(myImage)>
<cfset ImageScaleToFit(myImage,200,"","highestPerformance")>
<!--- Display the modified image in a browser. --->
<cfimage source="#myImage#" action="writeToBrowser">
Creating watermarks
A watermark is a semitransparent image that is superimposed on another image. One use for a watermark is for
protecting copyrighted images. To create a watermark in ColdFusion, you use the ImageSetDrawingTransparency
function with the ImagePaste function. You can create a watermark image in one of three ways:
Create a watermark from an existing image file. For example, you can use a company logo as a watermark.
Create a text image in ColdFusion and apply the image as a watermark. For example, you can create a text string,
such as Copyright or PROOF and apply it to all the images in a photo gallery.
Create a drawing image in ColdFusion and use it as a watermark. For example, you can use the drawing functions
to create a green check mark and apply it to images that have been approved.
Creating a watermark from an image file
The following example shows how to create a watermark from an existing GIF image located on a website:
974
<!--- This example shows how to create a watermark from an existing image. --->
<!--- Create two ColdFusion images from existing JPEG files. --->
<cfimage source="../cfdocs/images/artgallery/raquel05.jpg" name="myImage">
<cfimage source="http://www.google.com/images/logo_sm.gif" name="myImage2">
<cfimage source="#myImage#" action="write" destination="logo.jpg" overwrite="yes">
<cfset ImageSetDrawingTransparency(myImage,50)>
<!--- Paste myImage2 on myImage at the coordinates (0,0). --->
<cfset ImagePaste(myImage,myImage2,0,0)>
<!--- Write the result to a file. --->
<cfimage source="#myImage#" destination="watermark.jpg" action="write" overwrite="yes">
<!--- Display the result. --->
<img src="watermark.jpg"/>
975
<!--- This example shows how to draw a red circle with a line through it and use it as a
watermark. --->
<!--- Use the ImageNew function to create a ColdFusion image that is 201x201 pixels. --->
<cfset myImage=ImageNew("",201,201)>
<!--- Set the drawing transparency of the image to 30%. --->
<cfset ImageSetDrawingTransparency(myImage,30)>
<!--- Set the drawing color to red. --->
<cfset ImageSetDrawingColor(myImage,"red")>
<!--- Create an attribute collection that sets the line width to ten pixels. --->
<cfset attr=StructNew()>
<cfset attr.width = 10>
<!--- Apply the attribute collection to the ImageSetDrawingStroke function. --->
<cfset ImageSetDrawingStroke(myImage,attr)>
<!--- Draw a diagonal line starting at (40,40) and ending at (165,165) on myImage. The drawing
attributes you specified are applied to the line. --->
<cfset ImageDrawLine(myImage,40,40,165,165)>
<!--- Draw a circle starting at (5,5) and is 190 pixels high and 190 pixels wide. The drawing
attributes you specified are applied to the oval. --->
<cfset ImageDrawOval(myImage,5,5,190,190)>
<!--- Create a ColdFusion image from a JPEG file. --->
<cfimage source="../cfdocs/images/artgallery/raquel05.jpg" name="myImage2">
<!--- Scale the image to fit in a 200-pixel square, maintaining the aspect ratio of the
source image. --->
<cfset ImageScaleToFit(myImage2,200,200)>
<!--- Paste the myImage2 directly over the myImage. --->
<cfset ImagePaste(myImage,myImage2,0,0)>
<!--- Save the combined image to a file. --->
<cfimage source="#myImage#" action="write" destination="test_watermark.jpg" overwrite="yes">
<!--- Display the image in a browser. --->
<img src="test_watermark.jpg"/>
976
977
<!--- Save the thumbnail image to a file with the new filename. --->
<cfimage source="#myImage#" action="write"
destination="#newImageName#" overwrite="yes">
<cfoutput>
<p>
Thank you for uploading the image. We have created a thumbnail for
your picture.
</p>
<p>
<!--- Display the thumbnail image. --->
<img src="#getFileFromPath(newImageName)#">
</p>
</cfoutput>
</cfif>
<!--- If it is not a valid image file, delete it from the server. --->
<cfelse>
<cffile action="delete"
file="#fileUpload.serverDirectory#/#fileUpload.serverFile#">
<cfoutput>
<p>
The file you uploaded, #fileUpload.clientFile#, was not a valid image.
</p>
</cfoutput>
</cfif>
</cfif>
</cfif>
Verify that an image exists for records returned from the database.
Display the text, SOLD! on images that have been sold.
Resize images to 100 pixels, maintaining the aspect ratio of the source image.
Add a 5-pixel border to the images.
Display the modified images directly in the browser without writing them to files.
978
Example
<!--- Create a query to extract artwork and associated information from the cfartgallery
database. --->
<cfquery name="artwork" datasource="cfartgallery">
SELECT FIRSTNAME, LASTNAME, ARTNAME, DESCRIPTION, PRICE, LARGEIMAGE, ISSOLD, MEDIATYPE
FROM ARTISTS, ART, MEDIA
WHERE ARTISTS.ARTISTID = ART.ARTISTID
AND ART.MEDIAID = MEDIA.MEDIAID
ORDER BY ARTNAME
</cfquery>
<cfset xctr = 1>
<table border="0" cellpadding="15" cellspacing="0" bgcolor="#FFFFFF">
<cfoutput query="artwork">
<cfif xctr mod 3 eq 1>
<tr>
</cfif>
<!--- Use the IsImageFile function to verify that the image files extracted
from thedatabase are valid. Use the ImageNew function to create a
ColdFusion image fromvalid image files. --->
<cfif IsImageFile("../cfdocs/images/artgallery/#artwork.largeImage#")>
<cfset myImage=ImageNew("../cfdocs/images/artgallery/#artwork.largeImage#")>
<td valign="top" align="center" width="200">
<cfset xctr = xctr + 1>
<!--- For artwork that has been sold, display the text string "SOLD!"
in white on the image. --->
<cfif artwork.isSold>
<cfset ImageSetDrawingColor(myImage,"white")>
<cfset attr=StructNew()>
<cfset attr.size=45>
<cfset attr.style="bold">
<cfset ImageDrawText(myImage,"SOLD!",35,195, attr)>
</cfif>
<!--- Resize myImage to fit in a 110-pixel square, scaled proportionately. --->
<cfset ImageScaleToFit(myImage,110,"","bicubic")>
<!--- Add a 5-pixel black border around the images. (Black is the default color. --->
<!--- Add a 5-pixel black border to myImage. --->
<cfset ImageAddBorder(myImage,"5")>
<!--- Write the images directly to the browser without saving them to the hard drive.
--->
<cfimage source="#myImage#" action="writeToBrowser"><br>
<strong>#artwork.artName#</strong><br>
Artist: #artwork.firstName# #artwork.lastName#<br>
Price: #dollarFormat(artwork.price)#<br>
#artwork.mediaType# - #artwork.description#<br>
</td>
</cfif>
<cfif xctr-1 mod 3 eq 0>
</tr>
</cfif>
</cfoutput>
</table>
979
980
<!--- Verify whether the text entered by the user matches the CAPTCHA string. --->
<cfif #form.hashval# eq Hash(#form.userInput#)>
<cfoutput>
<p>
Thank you for registering for our online newsletter, #form.firstName# #form.lastName#.
</p>
<p>
A notification has been sent to your e-mail address: #form.mailTo#.
</p>
<cfmail from="[email protected]" to="#form.mailTo#" subject="Newsletter">
Thank you for your interest in our Newsletter.
</cfmail>
</cfoutput>
<cfelse>
<p>I'm sorry; please try again.</p>
</cfif>
On the first action page, clone the original image three times, change the sharpness setting for each clone, and display
the results:
981
On the second action page, save the selected image to the C drive:
982
About charts
The ability to display data in a chart or graph can make data interpretation much easier. Rather than present a simple
table of numeric data, you can display a bar, pie, line, or other applicable type of chart using colors, captions, and a
two-dimensional or three-dimensional representation of your data.
The cfchart tag, along with the cfchartseries and cfchartdata tags, provide many different chart types. The
attributes to these tags let you customize your chart appearance.
You can create 11 types of charts in Adobe ColdFusion in two and three dimensions. The following figure shows a
sample of each type of chart.
983
Note: In two dimensions, bar and cylinder charts appear the same, as do cone and pyramid charts.
984
Tag
Description
cfchart
Specifies the container in which the chart appears. This container defines the height, width, background color, labels,
fonts, and other characteristics of the chart.
Include at least one cfchartseries tag within the cfchart tag.
cfchartseries
Specifies a database query that supplies the data to the chart and one or more cfchartdata tags that specify
individual data points. Specifies the chart type, colors for the chart, and other optional attributes.
cfchartdata
The following example shows an outline of the basic code that you use to create a chart:
<cfchart>
<cfchartseries type="type">
<cfchartdata item="something" value="number">
</cfchartseries>
</chart>
The following example displays a simple pie chart that shows four values:
<cfchart>
<cfchartseries type="pie">
<cfchartdata item="New car sales" value="50000">
<cfchartdata item="Used car sales" value="25000">
<cfchartdata item="Leasing" value="30000">
<cfchartdata item="Service" value="40000">
</cfchartseries>
</cfchart>
Note: If you access charting functionality using Java calls, a watermark Developer Edition - Not for Production Use
might be displayed on the chart images. To avoid this, when you assign the server object to a reference, instead of
svr.getDefaultInstance(getPageContext().getServletContext());), use the following code (by prefixing
svr=) :svr=svr.getDefaultInstance(getPageContext().getServletContext());). Ensure that you restart
the server for the changes to take effect.
Charting data
One of the most important considerations when you chart data is the way that you supply the data to the cfchart tag.
You can supply data in the following ways:
985
This pie chart displays four types of revenue for a car dealer. Each cfchartdata tag specifies the income for a
department and a description for the legend.
Note: If two data points have the same item name, ColdFusion creates a graph of the value for the last one specified within
the cfchart tag.
The cfchartdata tag lets you specify the following information about a data point:
Attribute
Description
value
item
(Optional) The description for this data point. The item appears on the horizontal axis of bar and line charts, on
the vertical axis of horizontal bar charts, and in the legend of pie charts.
Charting a query
Each bar, dot, line, or slice of a chart represents data from one row/column coordinate in your result set. A related
group of data is called a chart series.
Because each bar, dot, line, or slice represents the intersection of two axes, craft the query result set such that the row
and column values have meaning when displayed in a chart. Often, doing so requires you aggregate data in the query.
You typically aggregate data in a query using one of the following:
Specify a SQL aggregate function (SUM, AVG, MAX, and so on) using a GROUP BY clause in the SELECT
statement.
986
This example displays the values in the AvgByDept column of the DataTable query. It displays the Dept_Name column
value as the item label by each bar.
The following table lists the attributes of the cfchartseries tag that you use when working with queries:
Attribute
Description
query
The query that contains the data. Also specify the valueColumn and itemColumn.
valueColumn
itemColumn
The query column that contains the description for this data point. The item normally appears on the horizontal
axis of bar and line charts, on the vertical axis of horizontalbar charts, and in the legend in pie charts.
987
2 Save the page as chartdata.cfm in the myapps directory under the web root directory. For example, the directory
http://localhost/myapps/chartdata.cfm
Note: If a query contains two rows with the same value for the itemColumn attribute, ColdFusion graphs the last row in
the query for that value. For the preceding example, if the query contains two rows for the Sales department, ColdFusion
graphs the value for the last row in the query for Sales.
Reviewing the code
The following table describes the code and its function:
988
Code
Description
<cfchart
xAxisTitle="Department"
yAxisTitle="Salary Average"
font="Arial"
gridlines=6
showXGridlines="yes"
showYGridlines="yes"
showborder="yes"
show3d="yes"
>
<cfchartseries
type="bar"
query="DeptSalaries"
valueColumn="AvgByDept"
itemColumn="Dept_Name"
seriesColor="olive"
paintStyle="plain"
/>
</cfchart>
You can also rewrite this example to use the cfoutput and cfchartdata tags within the cfchartseries tag, instead
of using the loop, to round the salary data, as the following code shows:
<cfchartseries
type="bar"
seriesColor="olive"
paintStyle="plain">
<cfoutput query="deptSalaries">
<cfchartdata item="#dept_name#" value=#Round(AvgByDept/1000)*1000#>
</cfoutput>
</cfchartseries>
989
One use of combining queries and data points is to provide data that is missing from the database; for example, to
provide the data for one department if the data for that department is missing. The example in the following procedure
adds data for the Facilities and Documentation departments to the salary data obtained from the query shown in the
previous section:
1 Open the chartdata.cfm file in your editor.
2 Edit the cfchart tag so that it appears as follows:
<cfchart chartwidth="600">
<cfchartseries
type="bar"
query="DeptSalaries"
itemColumn ="Dept_Name"
valueColumn="AvgByDept"
>
<cfchartdata item="Facilities" value="35000">
<cfchartdata item="Documentation" value="45000">
</cfchartseries>
</cfchart>
3 Save the page as chartqueryanddata.cfm in the myapps directory under the web root directory. For example, the
http://localhost/myapps/chartqueryanddata.cfm
The following image shows these options for combining two bar charts:
990
You can also combine chart types. The following is a combination bar and line chart:
The only chart type that you cannot mix with others is the pie chart. If you define one of the data series to use a pie
chart, no other chart appears.
The example in the following procedure creates the chart in the previous figure, which shows a bar chart with a line
chart added to it. In this example, you chart the salary of permanent employees (bar) against contract employees (line).
Note: The layering of multiple series depends on the order that you specify the cfchartseries tags. For example, if you
specify a bar chart first and a line chart second, the bar chart appears in front of the line chart in the final chart.
Create a combination bar chart and line chart
1 Open the chartdata.cfm file in your editor.
2 Edit the cfchart tag so that it appears as follows:
991
<cfchart
backgroundColor="white"
xAxisTitle="Department"
yAxisTitle="Salary Average"
font="Arial"
gridlines=6
showXGridlines="yes"
showYGridlines="yes"
showborder="yes"
>
<cfchartseries
type="line"
seriesColor="blue"
paintStyle="plain"
seriesLabel="Contract Salaries"
>
<cfchartdata item="HR" value=70000>
<cfchartdata item="Marketing" value=95000>
<cfchartdata item="Sales" value=80000>
<cfchartdata item="Training" value=93000>
</cfchartseries>
<cfchartseries
type="bar"
query="DeptSalaries"
valueColumn="AvgByDept"
itemColumn="Dept_Name"
seriesColor="gray"
paintStyle="plain"
seriesLabel="Dept. Average Salaries"
/>
</cfchart>
3 Save the file as chart2queries.cfm in the myapps directory under the web root directory.
4 Return to your browser and view the chart2queries.cfm page.
beige
blue
default
red
silver
992
yellow
To use any of these styles, specify the style using the style attribute of the cfchart tag. The following example
illustrates using the beige style:
<cfchart style="beige">
<cfchartseries type="pie">
<cfchartdata item="New car sales" value="50000">
<cfchartdata item="Used car sales" value="25000">
<cfchartdata item="Leasing" value="30000">
<cfchartdata item="Service" value="40000">
</cfchartseries>
</cfchart>
You can specify the appearance of charts by using the attributes of the cfchart and cfchartseries tags.
You can optionally specify the following characteristics to the cfchart tag on the types of charts indicated:
Chart characteristic
Attributes used
Description
Chart type
File type
format
Whether to send the chart to the user as a JPEG, PNG, or SWF file.
The SWF file is the default format.
All
Size
chartWidth
The width and height, in pixels, of the chart. This size defines the
entire chart area, including the legend and background area
around the chart.
All
chartHeight
The default height is 240 pixels; the default width is 320 pixels.
Color
foregroundColor
dataBackgroundColor
backgroundColor
You can specify 16 color names, use any valid HTML color format,
or specify an 8-digit hexadecimal value to specify the RGB value
and transparency. If you use numeric format, use double number
signs; for example, blue or ##FF33CC. To specify the color and
transparency, use the format ##xxFF33CC, where xx indicates the
transparency. The value FF indicates opaque; the value 00
indicates transparent. For the complete list of colors, see
Configuring and Administering ColdFusion.
All
993
Chart characteristic
Attributes used
Description
Labels
font
The font attribute specifies the font for all text. The default value All
is Arial. If you are using a double-byte character set on UNIX, or
using a double-byte character set in Windows with a file type of
Flash, specify ArialUnicodeMs as the font.
fontSize
fontBold
frontItalic
labelFormat
xAxisTitle
yAxisTitle
Chart type
Border
showBorder
Use the showBorder attribute to draw a border around the chart. All
The foregroundColor attribute specifies the border color. The
default value is no.
Grid lines
showXGridlines
Area
Cone
showYGridlines
gridLines
Bar
Curve
Cylinder
Horizontalbar
Line
Pyramid
Scatter
Step
Slice style
pieSliceStyle
Pie
Markers
showMarkers
All
markerSize
994
Chart characteristic
Attributes used
Description
Chart type
Value axis
scaleFrom
Area
scaleTo
Bar
Cone
Note: If you specify a scaleFrom or scaleTo attribute that would
result in cropping the chart, cfchart uses a value that shows the Curve
entire chart without cropping.
Cylinder
Horizontalbar
Line
Pyramid
Scatter
Step
Axis type
XAxisType
sortXAxis
Area
Horizontalbar
Bar
If the XAxisType attribute value is scale, the x axis is numeric.
All cfchartdataitem attribute values must be numeric, and the Cone
axis is automatically sorted numerically. The scale value lets you Curve
create graphs of numeric relationships, such as population
Cylinder
against age.
Line
Pyramid
Scatter
Step
3D appearance
show3D
xOffset
yOffset
All
Multiple series
showLegend
seriesPlacement
The showLegend attribute lets you display the chart legend when All
the chart contains more than one series of data. The default value
is Yes.
The seriesPlacement attribute specifies the location of each
series relative to the others. By default, ColdFusion determines the
best placement based on the graph type of each series.
Tips
tipStyle
tipBGColor
The tipStyle attribute lets you display a small pop-up window All
that shows information about the chart element pointed to by the
mouse pointer. Options are none, mousedown, or mouseover.
The default value is mouseover.
The tipBGColor attribute specifies the background color of the
tip window for Flash format only. The default value is white.
You can also use the cfchartseries tag to specify attributes of chart appearance. The following table describes these
attributes:
995
Chart characteristic
Attributes used
Description
Chart type
Multiple series
seriesLabel
The seriesLabel attribute specifies the text that displays for the
series label.
All
seriesColor
paintStyle
Specifies the way color is applied to a data series. You can specify All
solid color, raised button, linear gradient fill with a light center and
darker outer edge, and gradient fill on lighter version of color. The
default value is solid.
colorList
A comma-separated list of colors to use for each data point for bar, Pie
pyramid, area, horizontalbar, cone, cylinder, step, and pie charts.
You can specify 16 color names, use any valid HTML color format, or
specify an 8-digit hexadecimal value to specify the RGB value and
transparency. If you use numeric format, use double number signs;
for example, blue or ##FF33CC. To specify the color and
transparency, use the format ##xxFF33CC, where xx indicates the
transparency. The value FF indicates opaque; the value 00 indicates
transparent. For the complete list of colors, see Configuring and
Administering ColdFusion.
If you specify fewer colors than data points, the colors repeat. If you
specify more colors than data points, the extra colors are not used.
Data markers
markerStyle
Specifies the shape used to mark the data point. Shapes include
Curve
circle, diamond, letterx, mcross, rcross, rectangle, snow,
and triangle. Supported for two-dimensional charts. The default Line
value is rectangle.
Scatter
Labels
dataLabelStyle
Specifies the way in which the color is applied to the item in the
All
series Styles include None,Value, Rowlabel, Columnlabel, and
Pattern.
996
Note: To use the chart style file in the cfchart tag, you can only make the modifications indicated in the table that
follows this procedure.
4 Click the XML style tab.
5 Click the Save button in the lower-right corner.
6 Specify the name of the file; for example, mystyle.xml.
7 Specify the directory in which you want to save the chart style file.
Note: ColdFusion uses the same rules to look for the chart style XML files as it does for files included using the
cfinclude tag. For more information, seecfinclude.
8 Click Save.
The following table lists the attributes of the cfchart and cfchartseries tags and the associated WebCharts3D
commands:
Attribute
WebCharts3D command
chartHeight
chartWidth
dataBackgroundColor
font
fontBold
fontItalic
fontSize
font: Size
foregroundColor
foreground
gridlines
X-axis: labelcount
labelFormat
markerSize
Elements: markerSize
pieSliceStyle
rotated
scaleFrom
scaleTo
seriesPlacement
Elements: place
show3D
is3D
showBorder
997
Attribute
WebCharts3D command
showLegend
Legend: isVisible
showMarkers
Elements: showMarkers
showXGridlines
Frame: isVGridVisible
showYGridlines
Frame: isHGridVisible
tipbgColor
Popup: background
tipStyle
url
xAxisTitle
xAxisType
xOffset
Frame: xDepth
yAxisTitle
yAxisType
yOffset
Frame: yDepth
The following table lists the attributes of the cfchartseries tag and the associated WebCharts3D commands:
Attribute
WebCharts3D command
colorlist
markerStyle
Elements: series: Marker type: Rectangle | Triangle | Diamond | Circle | Letter | MCROSS | Snow |
RCROSS
paintStyle
seriesColor
seriesLabel
Elements: series:
type
998
Description
scaleFrom=40000
scaleTo=100000
Set the maximum value of the vertical axis to 100000. The minimum value is the default, 0.
font="arial"
fontSize=16
gridLines = 4
Displays four grid lines between the top and bottom of the chart.
show3D = "yes"
foregroundcolor="##000066"
databackgroundcolor="##FFFFCC"
seriescolor="##33CC99"
paintstyle="shade"
999
1000
Code
Description
SUM(Salary) AS SumByDept,
In the DeptSalaries query, add a SUM aggregation function to get the sum of all
salaries per department.
<cfset
In the cfloop tag, round the salary sums to the nearest thousand.
DeptSalaries.SumByDept[i]=Round(DeptSalari
es.SumByDept[i]/ 1000)*1000>
<cfchart
tipStyle="mousedown"
font="Times"
fontsize=14
fontBold="yes"
backgroundColor = "##CCFFFF"
show3D="yes"
>
Show a tip only when a user clicks the chart, display text in Times bold font, set the
background color to light blue, and display the chart in three dimensions.
<cfchartseries
type="pie"
query="DeptSalaries"
valueColumn="SumByDept"
itemColumn="Dept_Name"
Create a pie chart using the SumByDept salary sum values from the DeptSalaries
query.
Use the contents of the Dept_Name column for the item labels displayed in the
chart legend.
colorlist="##6666FF,##66FF66,##FF6666,##66 Get the pie slice colors from a custom list, which uses hexadecimal color numbers.
CCCC"
The double number signs prevent ColdFusion from trying to interpret the color
/>
1001
4 Add the following cfchart tag before the end of the body tag block:
<!--- Area-style Line chart, from HireSalaries Query of Queries. --->
<cfchart
chartWidth=400
BackgroundColor="##FFFF00"
show3D="yes"
>
<cfchartseries
type="area"
query="HireSalaries"
valueColumn="AvgByStart"
itemColumn="StartDate"
/>
</cfchart>
<br>
1002
Code
Description
Employee.StartDate,
Add the employee start date to the data in the GetSalaries query.
Use a cfloop tag to extract the year of hire from the hire data, and
convert the result to a four-digit number.
Create a second query from the GetSalaries query. This query contains
the average salary for each start year.
<cfchart
chartWidth=400
BackgroundColor="##FFFF00"
show3D="yes"
>
<cfchartseries
type="area"
query="HireSalaries"
valueColumn="AvgByStart"
itemColumn="StartDate"
/>
</cfchart>
Create an area chart using the HireSalaries query. Chart the average
salaries against the start date.
Limit the chart width to 400 pixels, show the chart in three dimensions,
and set the background color to white.
Administering charts
Use the ColdFusion Administrator to administer charts. In the Administrator, you can choose to save cached charts
in memory or to disk. You can also specify the number of charts to cache, the number of charting threads, and the disk
file for caching images to disk.
ColdFusion caches charts as they are created. In that way, repeated requests of the same chart load the chart from the
cache rather than having ColdFusion render the chart over and over again.
Note: You do not have to perform any special coding to reference a cached chart. Whenever you use the cfchart tag,
ColdFusion inspects the cache to see if the chart has already been rendered. If so, ColdFusion loads the chart from the
cache.
The following table describes the settings for the ColdFusion charting and graphing engine:
1003
Option
Description
Cache Type
Sets the cache type. Charts can be cached in memory or to disk. Caching in memory is faster, but more memory
intensive.
Maximum number of
images in cache
Specifies the maximum number of charts to store in the cache. When the limit is reached, the oldest chart in the
cache is deleted to make room for a new one. The maximum number of charts you can store in the cache is 250.
Specifies the maximum number of chart requests that can be processed concurrently. The minimum number is
1 and the maximum is 5. Higher numbers are more memory-intensive.
When caching to disk, specifies the directory in which to store the generated charts.
2 Save the page as chartToFile.cfm in myapps under the web root directory.
3 View the chartToFile.cfm page in your browser.
1004
Code
Description
<cffile action="WRITE"
file="c:\inetpub\wwwroot\charts\vehicle.jpg"
output="#myChart#">
You can use the following variables in the url attribute to pass additional information to the target page:
For example, to let users click the graph to open the page moreinfo.cfm, and pass all three values to the page, you use
the following URL:
url="moreinfo.cfm?Series=$SERIESLABEL$&Item=$ITEMLABEL$&Value=$VALUE$"
The variables are not enclosed in number signs like ordinary ColdFusion variables. They are enclosed in dollar signs.
If you click a chart that uses this url attribute value, it could generate a URL in the following form:
http://localhost:8500/tests/charts/moreinfo.cfm?
Series=Department%20Salaries&Item=Training&Value=86000
You can also use JavaScript in the URL to execute client-side scripts. For an example, see Linking to JavaScript from
a pie chart on page 1007.
1005
2 Save the page as Salary_details.cfm in the myapps directory under the web root directory.
1006
Code
Description
<cfquery name="GetSalaryDetails"
datasource="cfdocexamples">
SELECT Departmt.Dept_Name,
Employee.FirstName,
Employee.LastName,
Employee.StartDate,
Employee.Salary,
Employee.Contract
FROM Departmt, Employee
WHERE Departmt.Dept_Name = '#URL.Item#'
AND Departmt.Dept_ID = Employee.Dept_ID
ORDER BY Employee.LastName, Employee.Firstname
</cfquery>
Get the salary data for the department whose name was passed in
the URL parameter string. Sort the data by the last and first names
of the employee.
Display the data retrieved by the query as a table. Format the start
date into standard month/date/year format, and format the salary
with a leading dollar sign, comma separator, and no decimal
places.
1007
Code
Description
url = "Salary_Details.cfm?Item=$ITEMLABEL$"
When the user clicks a wedge of the pie chart, call the Salary_details.cfm
page in the current directory, and pass it the parameter named Item that
contains the department name of the selected wedge.
2 Save the page as chartdata_withJS.cfm in the myapps directory under the web root directory.
3 View the chartdata_withJS.cfm page in your browser:
4 Click the slices of the pie chart to display the pop-up window.
Page numbers
Headers and footers
1008
Page breaks
Clickable hypertext links when viewed online
ColdFusion provides the following tags for generating printable output:
cfdocument: Creates printable output and returns it to the browser or saves it in a file. For more information, see
Creating PDF and FlashPaper output with the cfdocument tag on page 1008.
cfreport: Uses the specified report definition to create printable output and return it to the browser or save it in
ColdFusion Report Builder: The ColdFusion Report Builder is a banded report writer that is integrated with
ColdFusion. For more information, see About Report Builder on page 1015.
Crystal Reports: Crystal Reports is a report writer whose report definitions you can use with the cfreport tag.
For more information, see Creating reports with Crystal Reports (Windows only) on page 1014.
ColdFusion printable reports are available in the following formats:
FlashPaper ColdFusion creates a SWF file. Clients must have an up-to-date version of Adobe Flash Player installed.
Adobe Acrobat ColdFusion creates a PDF file. Clients must have the Adobe Reader installed.
Microsoft Excel (ColdFusion reporting only) ColdFusion creates an Excel spreadsheet.
Note: The Excel report output format type provides limited support for the formatting options available in ColdFusion
reporting. Images and charts are not supported and numeric data containing formatting (such as commas, percents,
currency) appears as plain text in Excel. The Excel output format supports simple reports only and it is recommended that
you give careful design and layout consideration to reports designed for Excel output.
Crystal Reports (Windows only) ColdFusion passes control to Crystal Reports, which creates HTML. This option is
available with the cfreport tag only.
The cfdocument tag supports all HTML and CFML tags, with the following exceptions:
cfchart
1009
Page size
Page orientation
Margins
Encryption (PDF only)
User password and owner password (PDF only)
Permissions (PDF only)
For complete information on these options, see the cfdocument tag discussion in the CFML Reference.
Note: Embedding fonts in the report can help ensure consistent display across multiple browsers and platforms. For more
information on the considerations related to embedding fonts, see Creating a simple report on page 1036.
The following example displays a list of employees, using a cfoutput tag to loop through the query:
<cfdocument format="flashpaper">
<h1>Employee List</h1>
<!--- Inline query used for example purposes only. --->
<cfquery name="EmpList" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary, Contract
FROM Employee
</cfquery>
<cfoutput query="EmpList">
#EmpList.FirstName#, #EmpList.LastName#, #LSCurrencyFormat(EmpList.Salary)#,
#EmpList.Contract#<br>
</cfoutput>
</cfdocument>
cfdocumentsection: Divides output into sections, optionally specifying custom margins. Within a section, use the
cfdocumentitem tag to specify unique headers and footers for each section. Each document section starts on a new page.
With cfdocumentsection: The cfdocumentitem attribute applies only to the section, and overrides previously
specified headers and footers.
Without cfdocumentsection: The cfdocumentitem attribute applies to the entire document, as follows:
If the tag is at the top of the document, it applies to the entire document.
If the tag is in the middle of the document, it applies to the rest of the document.
If the tag is at the end of the document, it has no affect.
You can use the cfdocumentitem tag to create a running header for an entire document, as the following example
shows:
1010
<cfdocument format="PDF">
<!--- Running header --->
<cfdocumentitem type="header">
<font size="-3"><i>Directory Report</i></font>
</cfdocumentitem>
<h3>cfdirectory Example</h3>
<!--- Use cfdirectory to display directories by name and size --->
<cfdirectory
directory="#GetDirectoryFromPath(GetTemplatePath())#"
name="myDirectory" recurse="yes"
sort="directory ASC, name ASC, size DESC">
<!---- Output the contents of the cfdirectory as a cftable ----->
<cftable query="myDirectory"
htmltable colheaders>
<cfcol header="DIRECTORY:" text="#directory#">
<cfcol header="NAME:" text="#Name#">
<cfcol header="SIZE:" text="#Size#">
</cftable>
</cfdocument>
1011
<cfoutput>
<tr>
<td><font size="-1">
#empSalary.lastname#, #empSalary.firstname#</font>
</td>
<td align="right"><font size="-1">
#DollarFormat(empSalary.salary)#</font>
</td>
</tr>
<cfset deptTotal = deptTotal + empSalary.salary>
</cfoutput>
<tr>
<td align="right"><font size="-1">Total</font></td>
<td align="right"><font size="-1">#DollarFormat(deptTotal)#</font></td>
</tr>
<cfset deptTotal = 0>
</table>
</cfdocumentsection>
</cfoutput>
</cfdocument>
Note: You can use the cfdocument scope variables in expressions within the cfdocumentitem tag only.
You typically use these variables in a header or footer to display the current page number and total number or pages,
as the following example shows:
<cfdocumentitem type= "footer> #cfdocument.currentpagenumber# of
#cfdocument.totalpagecount#</cfdocumentitem>
1012
1013
Security option
Description
Encryption
Use the encryption attribute to specify whether PDF output is encrypted. Specify one of the following:
128-bit
40-bit
none
User password
Use the userpassword attribute to specify a password that users must enter to view the document.
Owner password
Use the ownerpassword attribute to specify a password that users must enter to view and optionally modify
the document.
Additionally, the cfdocument tag supports the following Acrobat security permissions through the permissions
attribute. Specify one or more of the following values; separate multiple permissions with a comma:
Permission
Description
Printing
Modification
Specify the AllowModifyContents attribute to let viewers modify the document, assuming they have the
required software.
Copy
Specify the AllowCopy attribute to let viewers select and copy text from the document.
Annotation
Specify AllowModifyAnnotations to let viewers add comments to the document. If users add annotations,
they must save the PDF after making changes.
Screen readers
Fill in
Assembly
Specify AllowAssembly to enable users to create bookmarks and thumbnails, as well as insert, delete, and
rotate pages.
Degraded printing
Specify AllowDegradedPrinting to enable lower-resolution printing. This format prints each page as a
bitmap, so printing can be slower.
Note: The defaults for these options vary, based on encryption level. These options apply to PDF only. For more
information, see the cfdocument discussion in the CFML Reference.
The following example creates a PDF document that allows copying only:
<cfdocument format="PDF" encryption="40-bit"
ownerpassword="us3rpa$$w0rd" userpassword="us3rpa$$w0rd"
permissions="AllowCopy" >
<h1>Employee List</h1>
<cfquery name="EmpList" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary
FROM Employee
</cfquery>
<cfoutput query="EmpList">
#EmpList.FirstName#, #EmpList.LastName#, #LSCurrencyFormat(EmpList.Salary)#<br>
</cfoutput>
</cfdocument>
1014
example shows the cfreport tag invoking a Crystal Reports report definition and passing a filter condition:
<cfreport report = '/reports/monthlysales.rpt'>
{Departments.Department} = 'International'
</cfreport>
ColdFusion uses COM to call Craxdrt9.dll for Crystal Reports version 9, and Craxdrt.dll for Crystal Reports version
10. If you have problems with the cfreport tag, ensure that these DLLs are registered and, if not, use regsvr32 to
register them (the default location for these DLLs is C:\Program Files\Crystal Decisions\Report Designer Component\).
For complete information on defining reports in Crystal Reports, see the Crystal Reports documentation.
1015
RDS
Remote Development Services (RDS) is a proprietary protocol that uses HTTP to enable the Query Builder and Chart
Wizard to access database data through a ColdFusion data source. To enable this functionality in the Report Builder, you
define settings for an RDS server. RDS server is another name for an associated ColdFusion server that has enabled RDS.
For more information, see Using CFML in reports on page 1030.
Run time
At run time, you display the CFR file by using a ColdFusion server that has ColdFusion Reporting enabled. You can
display the CFR file directly or run it through the cfreport tag. Also, you can save the report to a file instead of
returning output to the browser. If the report requires input parameters or a passed query, use the cfreport tag. If
you pass a query attribute in the cfreport tag, it overrides any internal SQL statement in the report definition.
Getting started
For installation instructions, see Installing ColdFusion. When you install the Report Builder, it also registers Windows
DLLs that RDS uses. If these DLLs fail to register properly, the Report Builder generates errors at startup and when
using RDS.
1016
Setup Wizard
The first time you start the Report Builder, it runs the Setup Wizard. The Setup Wizard prompts you to define default
settings for an associated ColdFusion server. These settings include the following:
URL for the web root used by the associated ColdFusion server (for example, http://localhost or
http://localhost:8500).
After running the Setup Wizard, the Report Gallery dialog box appears. When you click the Using A Report Wizard
radio button, the Report Builder runs the Report Creation Wizard, which prompts you for information and
automatically generates a complete report definition.
For more information on the Report Creation Wizard, see the Report Builder online Help.
Configuring RDS
Configure one RDS server for each ColdFusion server for which you define reports. After you configure an RDS server,
you can use the Query Builder to access data sources that you defined in the associated ColdFusion server, and select
database columns for use as query fields in a report.
Builder.
Host name The host on which ColdFusion runs. Type localhost or an IP address.
Port Web server port number. Accept the default port (80) or enter the port number of the ColdFusion servers
built-in web server (8500 is the default port number).
Context Root (J2EE configuration only) The context root (if any) for the ColdFusion web application.
Use Secure Sockets Layer (Optional) Enables SSL security.
User Name Not applicable to ColdFusion RDS.
Password RDS password. You set this password in the ColdFusion Administrator.
1017
Do not confuse the RDS password with the ColdFusion Administrator password, which you also manage through
the ColdFusion Administrator.
Prompt for password Specifies whether to prompt for an RDS password each time you use the Query Builder. If
you select this option, leave the User Name and Password fields blank.
The Report Builder automatically connects to the specified server when you display the Query Builder or Chart
Wizard.
Toolbox: Contains nonvariable elements placed in a report, including text, shapes, images, subreports, and graphs.
To use toolbox elements, click the element, and then drag in the report band to define the elements size. After you
place an element on a report band, you can modify its appearance and behavior by using the Properties panel.
Alignment panel: Use Control-click or Shift-click to select multiple elements in a report band, and then click the
appropriate alignment icon. You can also use Control+A to select all elements in a report band.
Report bands: Place toolbox elements, query fields, and calculated fields on report bands. The default report bands
are report header, page header, column header, page footer, report footer, and watermark. Page header, page footer,
and watermark are closed by default; to open them drag one of the adjacent splitter bars. To define additional bands
for groups, select Report > Group Management.
ColdFusion provides three panels that you use to place and format data elements in the workspace:
Properties panel: Contains display and report characteristics for the selected field. To display the Properties panel,
choose Window > Properties Inspector from the main menu. To change a property value, type or select a new value,
and press Enter. For complete information on properties, see the Report Builder online Help.
Fields and parameters panel: Contains items for query fields, input parameters, and calculated fields. To display
the Fields and parameters panel, choose Window > Fields and Parameters from the main menu. Use the add, edit,
and delete icons to manage these fields. After you define a field, drag the field name to add the field, its associated
label, or both, to a report band.
Report styles panel: Contains the styles that you define for a report. To display the Report styles panel, choose
Window > Report Styles from the main menu. Use the add, edit, and delete icons to manage report styles. After you
define styles, you apply them to elements on the report instead of specifying font, font size, and so on, for each
individual element. If your report layout, platform, or font availability requirements change, you can modify the
style to apply the changes throughout the report. Additionally, you can specify a style as the default for the report:
if no other style is applied to an element in the report, Report Builder applies the default style to that element.
The View menu lets you control whether toolboxes and panel windows appear. Also, you can click a windows title to
undock it and drag it to another area of the screen. For example, you can drag all three panels and dock them in the
same window. Report Builder lets you switch between them by clicking the tabs at the top of the window. To redock a
tool window or panel, drag it to the side or corner until a rectangle appears, and then release the mouse button.
For more information, see Common reporting tasks and techniques on page 1019 and the online Help.
1018
calculated totals on individual rows, use SQL. For more information, see Common reporting tasks and
techniques on page 1019.
Input parameters Does the report require variable input? If so, define an input parameter and pass values to the
report at run time by using the cfreportparam tag. For more information, see Common reporting tasks and
techniques on page 1019.
report. For example, use this option if your application has a form that your clients use to construct dynamic
selection criteria.
1019
ColdFusion requires these fonts to render the report accurately. ColdFusion automatically locates Acrobat built-in
fonts and fonts stored in typical font locations (such as the Windows\fonts directory). However, if your server has
additional fonts installed in nonstandard locations, register them with the ColdFusion Administrator so that the
cfdocument and cfreport tags can locate and render PDF and FlashPaper reports.
Client computer If your PDF report does not embed fonts, the fonts reside on the client computer to ensure consistent
report display.
Mapping logical fonts to physical fonts
If you are using Java logical fonts, such as serif, sans serif, or monospaced, ColdFusion maps these fonts to physical
fonts by using specifications in the cf_root/lib/cffont.properties file. (On the multiserver or J2EE configuration, this file
is in the cf_webapp_root/WEB-INF/cfusion/lib directory). You can modify these mappings, if necessary. Also, if you
are using an operating system whose locale is not English, you can create a locale-specific mapping file by appending
.java-locale-code to the filename. If ColdFusion detects that it is running on a non-English locale, it first checks for a
cffont.properties.java-locale-code file. For example, on a computer that uses the Chinese locale, name the file
cffont.properties.cn. For more information on Java locale codes, see the Sun website.
The ColdFusion install includes a cffont.properties.ja file for the Japanese locale.
This discussion applies to both the cfdocument and cfreport tags. For more information, see the Report Builder
online Help.
For this example, you can define two groups: one that corresponds to Country, and a second group that corresponds
to City. When you define more than one group, the Group Management dialog box appears with Up Arrow and Down
Arrow keys, which you can use to control group hierarchy. For example, country should precede city, because
countries contain cities.
1020
Define a group
1 Select Report > Group Management from the menu bar.
2 Click Add.
3 Specify a group name in the Name field.
4 Specify the value that controls grouping (also called a group expression) in the Group on field. At run time,
ColdFusion triggers a group break when the result of this value changes. These values are often query field names.
However, this value can also be a calculated field or other type of expression. Sample group expressions include the
following:
Query field Creates a group break when the associated column in the result set contains a different value. The field
that you specify must be one of the sort criteria for the result set; for example, query.country.
Calculated field Creates a group break when a calculated field returns a different value. For example, if the
expression calc.FirstLetter returns the first letter of a query column, you can group a report in alphabetical order.
Boolean expression Creates a group break when a Boolean expression returns a different value. For example, if
your result set is sorted by the passpercentage column, you could use the Boolean expression query.passpercentage
LT 50.
that page.
Reprint Header on Each Page Displays the group header on each page.
7 Click OK.
The Report Builder adds the group to the report and creates header and footer bands for the group.
8 Click OK again.
9 Add headings, text, query fields, calculated fields, and other information to the groups header and footer.
For more information on calculated fields, see the Report Builder online Help.
1021
Time
Long
Boolean
Double
Short
Byte
Float
Big Decimal
Date
Integer
String
Time Stamp
BLOB
CLOB
7 Click OK.
Note: The Query Builder defines query fields automatically for all database columns in the result set (this action does not
apply to the Advanced Query Builder). Also, if you run the Query Builder as part of the Report Creation Wizard, the
wizard places query fields on the report.
Define a calculated field
1 Choose Window > Fields and Parameters.
2 Click Calculated Fields.
3 Click the plus sign (+) at the upper edge of the tab.
4 Specify a name, default label text, and data type. Data type options are the same as for query fields.
5 Specify calculation options:
Calculation Specifies the type of calculation that ColdFusion performs. Valid values are: Average, Count,
DistinctCount, First, Highest, Lowest, Nothing, Standard Deviation, Sum, System, and Variance. If you specify
Nothing, you typically use the Perform Calculation On field to specify a dynamic expression. Except for Nothing
(for which you use the Perform Calculation On field) and System (for which you write a customized scriptlet class),
you use these calculations for group, page, and report totals.
Perform Calculation On Specifies a field or expression. Click the ... button to display the Expression Builder.
1022
Group.
Reset Group If Reset Field When is set to Group, use this field to specify the group whose group break triggers the
reset.
For additional information on calculated fields, see the Report Builder online Help.
Define an input parameter
1 Choose Window > Fields and Parameters.
2 In the Fields and Parameters panel, click Input Parameters.
3 Click the plus sign (+) at the upper edge of the tab.
4 In the Add Input Parameter dialog box, enter a value for the name field. This value must match an input parameter,
such as the name attribute of a cfreportparam tag included in the cfreport tag that uses the report definition.
5 Enter the default label text.
6 Specify a data type and default value, and click OK. Data type options are the same as for query fields.
For more information on using input parameters, see Using input parameters to pass variables and other data at run
time on page 1029 and Using subreports on page 1033.
Place a query field, calculated field, or input parameter on a report band
1 In the Fields and Parameters panel, use the radio buttons to specify whether to place the label, the field, or both.
2 Drag the query field, calculated field, or input parameter from the Fields and Parameters tab to the appropriate
report band.
3 Drag the query field, calculated field, or input parameter to the desired band.
4 (Optional) Use the Properties panel to customize the field display.
For example, you could have a query field named query.emp_salary and a calculated field that sums query.emp_salary,
resetting it with each group. Place query.emp_salary in the detail band, and the associated calculated field in the group
footer band.
1023
Note: ColdFusion trims leading and trailing blanks from labels. To include leading and trailing blanks, define a dynamic
field and include the blanks in the expression, for example, " My Title ".
Import image files
1 Click the Image icon in the toolbox.
2 Define the area for the image by dragging on the desired band.
3 In the Image File Name dialog box, navigate to the file that contains the image, select the file, and click OK.
Note: The BLOB column must contain a binary image in GIF, JPEG, or PNG format.
4 Click OK.
Note: These instructions assume that the contents of the BLOB column can be rendered as an image.
Add rectangles, ellipses, and lines
1 Click the rectangle, ellipses, or line icon in the toolbox.
2 Define the area or line by dragging on the desired band.
3 Resize the selected element by dragging the handles that surround it.
Pressing the Control key while resizing a rectangle, ellipsis, or line, constrains the element to a square, circle, or angles
that are multiples of 45 degrees.
Add dynamic fields
1 Click the Field icon in the toolbox.
2 Define the area for the dynamic field by dragging on the desired band.
The Add Field dialog box appears (if you havent defined any query fields, the Expression Builder appears).
3 Select the field to add. Selecting a query field, calculated field, or input parameter is the same as dragging from the
1024
The Expression Builder appears. This option is useful for calculations that use variables in the same row. For
example, to compute total price for an order detail line item, you could use the following expression:
LSNumberFormat((query.unitprice * query.quantity), ",_.__")
5 Click OK.
Aligning elements
Organized element layout is essential to a visually pleasing report. You achieve this organization by aligning, spacing,
and centering visual elements on each band relative to each other, to the band itself, and to elements on other bands.
The Report Builder Align Palette includes the following options:
The Align Palette options are also available from Modify > Alignment on the menu bar.
For complete information on fine-tuning element display, see the Report Builder online Help.
1025
Note: When choosing fonts for your report, ensure that the fonts are available on the server that runs ColdFusion and (if
you dont embed fonts) on the client computer. For more information on fonts, see Creating a simple report on
page 1036.
Define a style
1 Choose Window > Report Styles.
2 Click the (+) icon at the upper edge of the Report Styles tab.
3 Type a value for the Name field. Style names must be unique.
4 Add other style characteristics, and click OK.
Previewing reports
Report building is an iterative process and most developers periodically display the in-progress report to review their
most recent changes. If your report uses an internal query and you established default web root settings, preview
functionality is enabled automatically. If your report uses a passed query, define an associated CFM page and associate
that page with the report. The Report Builder runs this page when you request Report Preview.
Preview a report that uses an internal query
1 (Optional) Define default server connection information using the Preferences dialog box, if you did not define
these settings previously:
Default RDS server configuration (used for Query Builder and Chart Wizard only; not required for report
preview).
Fully qualified path for the local web root directory; for example, C:\ColdFusion\wwwroot or
C:\Inetpub\wwwroot.
URL for the local web root, for example, http://localhost:8500 or http://localhost.
2 (Optional) Specify the output format in the Report Properties dialog box (the default format is FlashPaper).
3 (Optional) If a CFM page runs, specify the URL of the CFM page in the Report Properties dialog box.
4 Save your report.
5 Select File > Preview from the menu bar to display the report.
Note: If the Report Builder displays the Edit Preview Report URL dialog box instead of displaying the Preview window,
select Edit > Preferences from the menu bar and insure that the web root file and URL settings are correct on the Server
Connection pane.
1026
If your report is designed to accept a query object from a cfreport tag, associate a URL with the report. If necessary,
the Report Builder prompts for this URL when you preview the report. Otherwise, you can open the Report Properties
dialog box, and specify the URL of the CFM page in the Report Preview URL field.
You can use the cfreport tag to run a report, regardless of whether the report has an internal query or is passed a
query.
Preview with an associated CFM file
1 Select Report > Report Properties from the menu bar.
2 Specify the URL of the associated CFM page in the Report Preview URL field. This CFM page must contain a
cfreport tag whose template attribute specifies the current CFR file and, if necessary, passes a query in the query
attribute.
3 Save your report.
4 Press F12. Depending on the output format that you have chosen, the Preview Report window displays your report
The Add Field dialog box appears, listing all fields defined for the report, including built-in calculated fields and
input parameters.
3 Select calc.PAGE_NUMBER, and click OK.
You can use the Field tool to add any type of field (query field, calculated field, input parameter) to a report.
For information on the other built-in calculated fields, see the Report Builder online Help.
panel, as follows:
1027
4 Specify a PrintWhen expression for each element. For example, you could specify the following expression to
display one element when shippeddate is later than requireddate (that is, late) and another element when
shippeddate is earlier than requireddate:
First element query.shippeddate LTE query.requireddate
Second element query.shippeddate GT query.requireddate
5 Specify different display characteristics for each element. For example, if an order is late, display it in red text.
6 Set the Top, Left, Height, and Width properties to the same values for each element.
When you specify identical placement properties, you access the individual elements through the Layered Controls
menu.
Use the Layered Controls menu
1 Right-click on the top element.
2 Select Layered Controls > elementname from the pop-up menu. The Report Builder identifies each layered element
Using links
You can include hypertext links from query fields, calculated fields, input parameters, charts, and images to a variety
of destinations:
Advanced
1028
Columns
Page Layout
Printing
Colors and Style
Data
Font
Font Style
Formatting
Hyperlinks
Layout
Print Control
The Report Builder displays only groups that relate to the currently selected element.
Set or modify a property for an element in the workspace
1 Select the element.
2 (Optional) If the Properties panel is not already displayed, choose Window > Properties Inspector.
Displaying reports
Your application can run a report by displaying the CFR file in a browser or by displaying a CFM page whose cfreport
tag runs the report.
You can optionally use the cfreport tag to save the report to a file.
The cfreport tag supports advanced PDF encryption options. For more information, see cfreport in the CFML
Reference.
For information on report preview, see Previewing reports on page 1025.
Display a report by using the cfreport tag
1 Create a report, with or without an internal query.
1029
2 Create a CFM page and add a cfreport tag that runs the report. If the report does not use an internal query, also
populate a query and pass it using the query attribute. If the report uses an internal query and you use the query
attribute, the passed query overrides the internal query.
<cfquery name="northwindemployees" datasource="localnorthwind">
SELECT EmployeeID, LastName, FirstName, Title, City, Region, Country
FROM Employees
ORDER BY Country, City
</cfquery>
<CFREPORT format="PDF" template="EmpReport.cfr"
query="#northwindemployees#"/>
Note: ColdFusion does not render text that occurs before or after the cfreport tag.
3 Open a browser and display the CFM page.
the previous procedure. Include a filename attribute that specifies the fully qualified name of the file being created,
as the following example shows:
<CFREPORT format="PDF" template="emppicture.cfr"
filename="#GetDirectoryFromPath(GetTemplatePath())#/emppicture.pdf"
overwrite="yes"/>
If you write the report output to an HTML file, ColdFusion creates a directory located relative to the HTML file,
generates files for the images (including charts) in the report, and stores the image files in the directory. For more
information, see Exporting the report in HTML on page 1047.
Use the .pdf extension for PDF output format, the .swf extension for FlashPaper output format, .xml extension for
an XML file, .rtf extension for an RTF file, .html extension for HTML files, and the .xls extension for Excel format.
3 Open a browser and display the CFM page. ColdFusion generates the report, saves the file, and displays an empty
Using input parameters to pass variables and other data at run time
Input parameters are data fields that you pass to the report at run time. You can place input parameters directly on a
report band or you can use them as input to a calculated field.
1030
Define input parameters in the same manner as query fields. You can specify a default value that ColdFusion uses when
no corresponding parameter exists. For more information on defining input parameters, see Defining, modifying,
and using fields and input parameters on page 1021.
You use input parameters in the following ways:
Through the cfreportparam tag: Input parameters must correspond, by name, to cfreportparam tags embedded
in the CFM page invocation. For example, if you define an input parameter named ReportTime, you pass a
cfreportparam tag with a name attribute set to ReportTime, as the following example shows:
<cfreport format="PDF" template="FourthReport.cfr" query="#coursedept#">
<cfreportparam name="ReportTime" value="#DateFormat(Now())#, #TimeFormat(Now())#">
</cfreport>
Subreport parameters: When a subreport requires information from a main report, you define subreport
parameters in the main report and corresponding input parameters in the subreport. For more information, see
Using subreports on page 1033.
For information on dynamically populating input parameters at run time, see Advanced query mode on page 1030.
1031
Another possible use of advanced query mode is to test for passed parameters in the URL or FORM scopes and use
those parameters to retrieve data, as the following example shows:
<!--- First look for URL param. URL overrides cfreportparam. --->
<cfif isDefined("url.deptidin")>
<cfset param.deptidin = url.deptidin>
</cfif>
<!-- Then look for FORM param. Overrides URL param. --->
<cfif isDefined("form.deptidin")>
<cfset param.deptidin = form.deptidin>
</cfif>
<cfquery name="CFReportDataQuery" datasource="cfdocexamples">
SELECTLastName, FirstName, Dept_ID
FROMEmployee
WHERE (Dept_ID = #param.deptidin#)
</cfquery>
Commented code associated with the function appears in the right pane.
4 Modify the code and click OK.
are available for use. The following example shows a report function that concatenates address fields:
1032
<cfargument
<cfargument
<cfargument
<cfargument
<cfargument
<cfargument
name="Name" required="yes"/>
name="Address1" required="yes"/>
name="Address2" required="yes"/>
name="City" required="yes"/>
name="State" required="yes"/>
name="Zip" required="yes"/>
Using expressions
Many elements of the Report Builder (including query fields, calculated fields, input parameters, images, and report
object attributes) are single operand ColdFusion expressions. Because these elements are expressions, you can
manipulate them with CFML functions.
The Expression Builder is a graphical interface that lets you quickly apply CFML functions to Report Builder elements.
Uses for the Expression Builder include the following:
Many of the report object attributes (such as PrintWhen) accept expressions, which you can associate with query
parameters, input parameters, or ColdFusion page variables. You can tie report attributes and columns to display
based on run-time data or user preference.
1033
Concatenating fields
Formatting fields
Calculated fields
Accessing and displaying ColdFusion page variables and scopes
For information on using the Expression Builder, see Report Builder online Help.
For more information on expressions, see Using Expressions and Number Signs on page 64.
Using charts
Charts can help clarify large or complex data sets. The Report Builder lets you place a chart in any report band and
supports many types of charts.
To add a chart to a report, you use the Chart Wizard, which steps you through the chart building process. The Chart
Wizard, which is fully integrated with the Query Wizard to facilitate database-driven charts, helps you define the chart
type, the data used for the report and other formatting options.
As you use the Chart Wizard to choose and define the various aspects of a given chart, the Report Builder uses RDS
to generate chart images in real time. However, the data in these chart images is not real.
The Chart Wizard includes the following panels:
Chart Types: Select the chart type (for example, bar) and subtype (for example, 3D-stacked).
Chart Series: Select the data for the series. When you add a series, the Report Builder lets you hard-code series data
or open the Query Builder to populate the series using a database query.
Chart Formatting: Specifies title and series, general appearance, 3D appearance, lines and markers, and font.
The data you specify through the Chart Wizard corresponds to the attributes specified in the cfchart, cfchartseries, and
cfchartdata tags. For more information on these tags, see the CFML Reference.
For complete information on ColdFusion charting capabilities, see Creating Charts and Graphs on page 982. For
more information on charting using the Report Builder, see Report Builder online Help.
Using subreports
Subreports let you nest a report within your report. The data that you display in a subreport is typically related to the
data in the main report. You enable this display by passing one or more subreport parameters to the subreport.
However, the data displayed in a subreport can also be unrelated to the data in the main report.
Reasons to use subreports including the following:
1034
The following example shows the use of subreport parameters and the relationship between a report and a subreport:
mainreport.cfr
Subreport:
subreport.cfr
Subreport expression :
custid = #query.CustomerID
subreport.cfr
param.custid
SELECT CustomerID, CompanyName,
ContactName
FROM Customers
WHERE (CustomerID = '#param.custid#')
Note: Although the Report Builder supports multiple levels of nesting, it displays one level of nesting only.
For additional information on subreports, see the Report Builder online Help.
Defining a subreport
You can define a subreport and include it in a report, or you can define it as part of inserting the subreport in the main
report.
A subreport has the following characteristics:
Data displayed in the detail band only. A subreport uses no header or footer bands.
If the subreport is related to the main report, it must include an internal query that uses a SELECT statement with
a WHERE clause specifying the name of the input parameter used in the main reports Subreport Expression
property.
If you have already defined a subreport, you add it to the main report and define subreport parameters, as necessary.
Add an existing subreport
1 Define or open your main report.
2 Click the Subreport icon in the toolbox.
3 Drag an area for the subreport in the desired report band.
4 Select From An Existing Report, specify the subreport, and click Next.
5 Select the fields in the main report that correspond to fields in the subreport and click Next.
6 Click Finish.
The Report Builder adds the subreport to the main report, saving the report to subreport mappings as subreport
parameters.
7 To modify subreport parameter settings, select the subreport and click Subreport Parameters in the Properties
panel.
1035
If you are certain about the data required for a subreport, you can define a new subreport while adding it to the main
report.
Add a new subreport
1 Define or open your main report.
2 Click the Subreport icon in the toolbox.
3 Drag an area for the subreport in the report band.
4 Select As A New Report and click Next.
5 Click Query Builder.
6 Select the tables and columns for the subreport.
7 Specify a WHERE clause for the report by using the Condition and Criteria columns for the key columns.
Specify a WHERE for Condition and either ='#CFVariable#' (string column) or =#CFVariable# (numeric
column) for Criteria, and then overtype CFVariable with the name of the input parameter for the subreport (you
define the input parameter name later in the procedure.)
8 Click Save, and then click Next.
9 Specify grouping fields, if appropriate for your subreport, and click Next.
10 Specify Free Form or Grid, and click Next.
11 Specify Only Detail Band, and click Next.
12 Specify a color scheme, and click Next.
13 Specify headings, as appropriate, and click Next.
14 For each parameter required by the subreport, specify the following:
Parameter name.
Associated value from the main report (select from the pop-up menu).
Data type.
15 Click Next.
16 Specify a fully qualified filename for the subreport, and then click Next.
17 Click Finish.
Report Builder adds the subreport to the main report. Report Builder lets you change subreport name and modify
subreport parameters in a main report.
Modify subreport settings
1 Click the subreport element in the main report.
2 To change the subreport, modify Subreport Expression.
3 To modify subreport parameters:
a Click the Subreport Parameters property.
b Click the ... button.
c Add, modify, or delete subreport parameters, and click OK.
1036
Create a base report by using the Report Wizard and the Query Builder.
Use the Expression Builder to modify the data presentation in the report.
Modify the display text for column data.
Add a text field to the report and format text and data elements by using report styles.
Add an image file and images from a database.
Create and add a calculated field to display the total sales by artist.
Add group-level and report-level pie charts that show the ratio of sold and unsold art for each artist and for all the
artists in the database.
table pane. Notice that it automatically creates the join between the two tables based on the ARTISTID column.
e In the APP.ARTISTS table, double-click the FIRSTNAME and LASTNAME columns. The Query Builder adds
1037
In the ART table, double-click the ARTNAME, DESCRIPTION, PRICE, and ISSOLD columns. The following
example shows the completed query in the Query Builder:
1038
Change the display of the ISSOLD value to a yes/no expression. By default, Report Builder displays 0 (not sold) or
1 (sold) for the ISSOLD column based on how the data is stored in the database. You can use a function to change
the display to yes or no.
1039
Notice that the Expression Builder prompts you with the available field names as you type.
3 Click the OK button in the Expression Builder.
4 Choose File > Save from the Report Builder menu bar to save your changes to the report.
5 Press F12 to preview the report.
Report Builder displays the first and last name for each of the artists. Notice that the report still is grouped
alphabetically by last name.
6 Close the preview window.
This expression multiplies the total price of the artwork per artist by the number of items sold to calculate the
total sales per artist. If the ISSOLD value for a record is 1 (sold), the value is multiplied by 1 and added to the
total; if the ISSOLD value for a record is 0 (unsold), the value is multiplied by 0.
f
g Change the Reset Group value to LASTNAME, and click OK. Report Builder adds the calculated field definition
1040
4 Press F12 to preview the report. Report Builder displays the sum of the artwork sold for each artist.
Create a style
1 Choose Window > Report Styles from the main menu.
2 Click the (+) button.
3 In the Name field, enter GroupFooter.
4 Click the Color and Style tab and change the color to #9999CC.
5 Click the Font tab and change the Font to Tahoma and click the bold option. Then click OK. Report Builder adds
Adding images
When you add images with Report Builder, you can perform the following types of tasks:
Replace the company name text box with a company logo in the report header.
Use the Query Builder to add images from a database.
Display the report in RTF format for faster display.
Add a logo to the report header
1 Select the Company Name text box located in the header band preceding Sales Report.
2 Choose Edit > Cut to remove the text box from the report.
3 Click the Add Image icon in the Controls toolbox. (The icon has a picture of a tree on it.)
1041
4 Drag the mouse in the header band preceding the Sales Report text box. When you release the mouse, the Image
C:\ColdFusion9\wwwroot\cfdocs\getting_started\photos\somewhere.jpg
6 Click Open. Report Builder displays the Art World logo in the area that you selected.
7 With the image selected in the workspace, choose Windows > Properties Inspector. The Properties Inspector for
statement.
3 Click the Test Query button. A list of image filenames appears to the right of the ISSOLD column.
4 Close the Test Query window and click the Save button in the Query Builder.
5 In the Report window, expand the Detail band by clicking the lower splitter bar and dragging down.
6 Click the Add Image icon in the Controls toolbox and drag the mouse in Detail band of the report to the left of the
query.ARTNAME field. When you release the mouse, the Image File Name dialog box appears.
7 Navigate to the cfartgallery images directory:
C:\ColdFusion9\wwwroot\cfdocs\images\artgallery
8 In the File Name field, type #query.largeimage#.
9 Click the Open button. Report Builder adds the column to the Detail band of the report.
10 Align the image column with the top of the Detail band.
11 With the image element selected in the detail band, choose Window > Properties Inspector.
12 Change the following properties:
a Transparency: Transparent.
b Scale Image: Retain Shape. This option scales the images proportionately within the bounding box.
c Error Control: No Image. This option ensures that Report Builder displays blank images rather than generates
1042
Adding charts
You can use the Chart Builder to add two pie charts to your report: the first pie chart shows the total dollar amount of
the art sold versus the total dollar amount unsold art for each artist; the second pie chart shows the sum of artwork
sold versus unsold for all of the artists.
The two pie charts are the same except for the scope. To apply a pie chart to a group (the ratio of sold to unsold art for
each artist), add the pie chart to the group footer band. To apply the pie chart to the report (the ratio of sold to unsold
art for all artists), add the pie chart to the report footer band.
In Adding a calculated field on page 1039, you added a calculated field for the total dollar amount of artwork sold.
Before you can create the pie chart for this example, create a second calculated field for the total dollar amount of
unsold art.
Add a calculated field for the sum of unsold art
1 Choose Window > Fields and Parameters.
2 Select the Calculated Fields heading in the Fields and Parameters panel.
3 Click the (+) icon at the upper edge of the panel:
a In the Name field, type Unsold.
b In the Default Label Text field, type Unsold.
c In the Data Type field, choose Big Decimal from the pop-up menu.
d In the Calculation field, choose Sum from the pop-up menu.
e In the Perform Calculation On field, enter the following expression to calculate the dollar amount of unsold art:
Iif(IsBoolean(query.ISSOLD) and not(query.ISSOLD), query.Price,0)
In the Reset Field When field, choose Group from the pop-up menu.
1043
changes:
a In the Chart Title field, type Total Sales for #query.LASTNAME#.
b In the X Axis Title field, type Sold.
c In the Y Axis Title field, type Unsold.
d In the Label Format field, choose Currency from the pop-up menu.
e Click the 3-D Appearance tab and ensure that Show 3-D is selected.
7 Click the Font tab and make the following changes:
a Change the Font Name to Arial.
b Change the Font Size to 9.
8 Click the Finish button. Report Builder adds a place holder for the pie chart in the report.
9 Resize and move the chart to the desired location within the LASTNAME Footer band.
10 Choose File > Save to save your changes to the report.
11 Press F12 to preview the report.
TotalSold
TotalUnsold
Total Sold
Total Unsold
Data Type:
Big Decimal
Big Decimal
Calculation:
Sum
Sum
Iif(IsBoolean(query.ISSOLD) and
query.ISSOLD, query.Price,0)
Iif(IsBoolean(query.ISSOLD) and
not(query.ISSOLD), query.Price,0)
1044
Name
TotalSold
TotalUnsold
Initial Value:
Report (Changes)
Report (Changes)
Reset Group:
LASTNAME
LASTNAME
2 Expand the Report Footer band, which is located directly below the Page Footer band.
3 Copy the pie chart from the Group Footer and paste it in the Report Footer.
4 Double-click the pie chart and click the Next button.
5 Double-click Total Sales to display the Edit Chart Series dialog box.
6 Change the Series Label to Total Sales for Artists.
7 Change the chart series values:
Label
Value
Sold
#calc.TotalSold#
Unsold
#calc.TotalUnsold#
8 Click the Next button, and then Click the Title & Series tab.
9 Change the Chart Title to Total Sales for Artists, and click Finish.
10 Choose File > Save from the menu bar to save your changes to the report.
11 Press F12 to preview the report.
The Total Sales for Artists pie chart appears only on the last page of the report. Verify that the calculations are correct.
ReportTitle
CompanyName
PageTitle
ReportDate
SubTitle
DetailData (default style)
DetailLabel
PageFooter
RectangleStyle
LineStyle
The instructions on Adding and formatting fields on page 1040 show how to add a field called GroupFooter and
apply it to a text field and a data field in the GroupFooter band. You can export the styles in a report to a CSS file.
Report Builder automatically generates the CSS code for the styles. This technique is an efficient way to maintain a
single set of styles to use with multiple reports. You can modify the styles in the CSS file by using any text editor and
either import the CSS file in Report Builder or override the styles in the report at run time.
1045
1046
PageFooter
{
color:#2F2F2F;
font-size:8pt;
}
RectangleStyle
{
color:#E3EDEF;
background-color:#E3EDEF;
}
LineStyle
{
color:#CCCCCC;
background-color:#CCCCCC;
}
GroupFooter
{
color:Blue;
font-weight:bold;
font-family:Tahoma;
5 Change the ReportTitle style color attribute to Red and add the font-weight attribute, as the following code
shows:
ReportTitle
{
color:Red;
font-size:24pt;
font-weight: bold;
}
Also, you can override report styles from ColdFusion. Form more information, see Overriding report styles on
page 1048.
Note: If you add a style to the CSS file, add a style with the same name to the report in Report Builder. Also, Report Builder
does not support all CSS styles. For more information, see the cfreport tag in the CFML Reference.
Import the CSS file
1 Choose Window > Report Styles.
2 Click the import styles icon (the one with the blue arrow).
3 Navigate to the location of the artStyles.css file, and click OK. Report Builder automatically updates the report style
1047
The following code creates a simple login page in ColdFusion. The form uses artists last name as the user ID. (The
code does not include password verification):
<h3>Artist Login Form</h3>
<p>Please enter your last name and password.</p>
<cfform name="loginform" action="artSalesReport.cfm" method="post">
<table>
<tr>
<td>Last Name:</td>
<td><cfinput type="text" name="username" required="yes" message="A username is
required."></td>
</tr>
<tr>
<td>Password:</td>
<td><cfinput type="password" name="password" required="yes" message="A password is
required."></td>
</tr>
</table>
<br />
<cfinput type="submit" name="submit" value="Submit">
</cfform>
On the processing page, add a query like the one you created in the Report Builder report. The ColdFusion query must
contain at least all of the columns included in the Report Builder query; however, the ColdFusion query can contain
additional data.
The query in the following example selects all of the data from the ART and ARTISTS tables based on the artists last
name. The cfreport tag uses the pathname of the CFR file as the report template.
<cfquery name="artsales" datasource="cfartgallery">
SELECT *
FROMAPP.ART, APP.ARTISTS
WHERE APP.ART.ARTISTID = APP.ARTISTS.ARTISTID
AND APP.ARTISTS.LASTNAME= <cfqueryparam value="#FORM.username#">
ORDER BY ARTISTS.LASTNAME
</cfquery>
<cfreport query="#artsales#" template="ArtSalesReport1.cfr" format="RTF"/>
ColdFusion displays the report for the artist in RTF format. Notice that the value of the format attribute overrides the
Default Output format defined in the CFR file.
Exporting the report in HTML
To generate a report in HTML and display it directly in the browser, change the format attribute to HTML:
<cfreport template="ArtSalesReport1.cfr" format="HTML"/>
ColdFusion automatically generates a temporary directory where it stores all of the image files in the report (charts are
saved as PNG files). The location of the temporary directory is:
C:\ColdFusion9\tmpCache\CFFileServlet\_cfreport\_report[unique_identifier]
You can specify when the temporary directory is removed from the server by using the CreateTimeSpan function as
a value for the resourceTimespan attribute:
<cfreport query="#artsales#" template="ArtSalesReport1.cfr" format="HTML"
resourceTimespan="#CreateTimeSpan(0,1,0,0)#"/>
1048
You can specify the time span in days, hours, minutes, and seconds. In this example, the temporary directory is deleted
after one hour. For more information, see the CFML Reference.
To export the report output to an HTML file, specify the filename attribute. The following code writes the report
output to an HTML file called artSales.html:
<cfreport template="ArtSalesReport1.cfr" format="HTML" filename="artSales.html"
overwrite="yes"/>
ColdFusion creates an image directory relative to the HTML output file in the format filename_files. In this example,
ColdFusion automatically generates PNG files for the charts in the report and saves them to a directory called
artSales_files. Also, it generates copies of all of the JPG images extracted from the cfartgallery database and stores them
in the artSales_files directory. For more information, see the CFML Reference.
Overriding report styles
To override the report styles in a report, specify the style attribute of the cfreport tag. The value must contain valid
CSS syntax, the pathname to a CSS file, or a variable that points to valid CSS code. The CSS style names must match
the report style names defined in Report Builder.
The following code shows how to override the styles in the ArtSalesReport1.cfr report with the styles defined in the
artStyles.css file:
<cfreport template="ArtSalesReport1.cfr" style="artStyles.css" format="PDF"/>
The following code shows how to apply a CSS style as a value of the style attribute:
<cfreport template="ArtSalesReport1.cfr" style='ReportTitle {defaultStyle: false;
font-family:"Tahoma"; color: "lime";}' format="FlashPaper">
</cfreport>
The following code shows how to create a variable called myStyle and use it as a value of the style attribute:
<cfset mystyle='DetailData { defaultStyle: true; font-family: "Tahoma"; color: ##00FFF0;}'>
<cfreport template="ArtSalesReport1.cfr" style="#mystyle#" format="HTML">
</cfreport>
For more information, see the cfreport tag in the CFML Reference.
1049
Tag
Description
cfpresentation
Defines the look of the presentation and determines whether the presentation is saved to files or run
directly in the client browser.
cfpresentationslide
cfpresenter
A SWF file
An HTML file
HTML and CFML code in the cfpresentationslide start and end tags
Provides information about the person presenting a slide. You can assign a presenter to one or more
slides. Presenter information is displayed in the control panel for the duration of the slide.
You specify at least one slide for the presentation and can assign each presenter to one or more slides. The following
example shows a slide presentation with content from four different sources and two presenters:
<cfpresentation title="myPresentation">
<cfpresenter name="Tuckerman" title="V.P. of Marketing"
email="[email protected]">
<cfpresenter name="Anne" title="V.P. of Sales" email="[email protected]">
<cfpresentationslide src="slide1.swf" title="Overview" duration="10"
presenter="Anne"/>
<cfpresentationslide src="slide2.htm" title="Q1 Sales" duration="30"
presenter="Anne"/>
<cfpresentationslide src="http://www.markettrends.com/index.htm"
title="Market Trends" duration="30" presenter="Tuckerman"/>
<cfpresentationslide title="Summary" duration="10">
<h3>Summary</h3>
<ul>
<li>Projected Sales</li>
<li>Challenges Ahead</li>
<li>Long Term Goals</li>
</ul>
</cfpresentationslide>
</cfpresentation>
Note: The cfpresentationslide tag requires an end tag. If you specify a source file as the slide content, use the end
slash as a shortcut for the end tag.
When the presentation runs, the slides appear in the order they are listed on the ColdFusion page for the duration
specified in each slide. The presenter information is displayed in a control panel next to the slide to which it is assigned.
The title appears at the top of the control panel. The color settings affect the presentation interface, but not the format
of the slides within the presentation. Set the showNotes attribute to yes to display text notes that are defined for
individual slides.
1050
If you do not specify a directory, as in the previous example, ColdFusion runs the presentation directly in the client
browser. The presentation uses files written to a temp directory on the server. To save the presentation, specify an
absolute path or a directory relative to the CFM page. (ColdFusion does not create the directory; it must exist already.)
In the following example, the presentation files are stored in the salesPresentation directory on the local drive:
<cfpresentation title="Sales Presentation" directory="c:\salesPresenation">
ColdFusion automatically generates the following files necessary to run the presentation and saves them in the
specified directory:
components.swf
index.htm
loadflash.js
viewer.swf
Also, ColdFusion creates a subdirectory called data where it stores the following files:
Adding presenters
Optionally, you can add one or more presenters under the cfpresentation tag. ColdFusion displays the presenter
information in the control panel for the current slide to which it is assigned. A slide does not require a presenter.
Use the cfpresenter tag to specify personal information. This information can include a title, an e-mail address, a
logo and an image of the person, as the following code shows:
<cfpresentation title="Sales Presentation">
<cfpresenter name="Anne" title="V.P. of Sales" biography="Anne Taylor has been a top seller
at Widgets R Us for five years." logo="images/logo.jpg" image="images/ataylor_empPhoto.jpg"
email="[email protected]">
The name attribute is required. You use this value to assign the presenter to one or more slides. To assign a presenter
to a slide, use the cfpresenter tag name attribute value as the cfpresentationslide tag presenter attribute. The
following example creates a presenter named Tuckerman and assigns him to a slide called Overview:
<cfpresentation title="Sales Presentation">
<cfpresenter name="Tuckerman" title="V.P. of Marketing">
<cfpresentationslide title="Overview" src="overview.swf" presenter="Tuckerman"
duration="10"/>
...
</cfpresentation>
Note: Assign presenters explicitly to slides. To assign a presenter to more than one slide, use the presenter name in each
of the cfpresentationslide tags.
1051
When you assign a presenter to a slide, the presenter information is displayed in the control panel for the duration of
the slide. Images must be in JPEG format and the files must be located in a path relative to the ColdFusion page.
ColdFusion maps the email attribute value to the contact link in the control panel. This link opens an e-mail message
in the local e-mail application when you click it.
The following code creates three presenters for a presentation and assigns two of the presenters to slides:
<cfpresentation title="Sales Presentation">
<cfpresenter name="Hannah" title="V.P. of Marketing" image="hannah.jpg">
<cfpresenter name="Anne" title="V.P. of Sales" image="Anne.jpg">
<cfpresenter name="Wilson" title="V.P. of Engineering"
image="Wilson.jpg">
<cfpresentationslide title="Overview" presenter="Hannah" duration="30"
src="slide1.htm"/>
<cfpresentationslide title="Q1 Sales" presenter="Anne" duration="15"
src="slide2.htm"/>
<cfpresentationslide title="Projected Sales" presenter="Anne"
duration="15" src="slide3.htm" video="promo.flv"/>
<cfpresentationslide title="Conclusion" src="slide4.htm"/>
</cfpresentation>
The presenter Hannah is assigned to one slide and Anne is assigned to two slides. The last slide in the presentation has
no presenter assigned to it. Because Wilson is not assigned to a slide, his information does not appear in the
presentation. In the second slide, Annes photo is displayed in the control panel. In the third slide, however, the video
called promo.flv runs in place of Annes photo in the control panel for the duration of the slide. The video does not
display in the slide.
Note: Videos must be in SWF or FLV format. You cannot specify audio and video for the same slide.
Adding slides
Use one cfpresentationslide tag for each slide in the presentation. The presentation runs the slides in the order
they are listed beneath the cfpresentation tag. You can create content for a slide in one of the following ways:
Source
Description
Example
A URL
1052
In this example, ColdFusion generates the files required to run the presentation in the gardenPresentation directory.
It generates a new SWF file in the data subdirectory from each of the slides. ColdFusion also copies the hendrix.mp3
file and saves it in the data subdirectory.
Note: Links within slides created from HTML files are not active.
1053
Note: The value for the format attribute of the cfchart tag must be JPG or PNG.
The content for slides is not limited to static data: you can generate content from information extracted from a
database or a query of queries.
Sample presentations
This section provides two sample presentations.
Example 1
The following example creates a simple presentation that incorporates data retrieved from the cfdocexamples
database. It shows how to perform the following tasks:
1054
<!--- The following query extracts employee data from the cfdocexamples
database. --->
<cfquery name="GetSalaryDetails" datasource="cfdocexamples">
SELECT Departmt.Dept_Name,
Employee.FirstName,
Employee.LastName,
Employee.StartDate,
Employee.Salary,
Employee.Contract
From Departmt, Employee
Where Departmt.Dept_ID = Employee.Dept_ID
ORDER BY Employee.LastName, Employee.Firstname
</cfquery>
<!--- The following code creates a presentation with three presenters. --->
<cfpresentation title="Employee Satisfaction" primaryColor="##0000FF" glowColor="##FF00FF"
lightColor="##FFFF00" showoutline="no">
<cfpresenter name="Jeff" title="CFO" email="[email protected]"
logo="../cfdocs/getting_started/photos/somewhere.jpg"
image="../cfdocs/images/artgallery/jeff01.jpg">
<cfpresenter name="Lori" title="VP Marketing" email="[email protected]"
logo="../cfdocs/getting_started/photos/somewhere.jpg"
image="../cfdocs/images/artgallery/lori01.jpg">
<cfpresenter name="Paul" title="VP Sales" email="[email protected]"
logo="../cfdocs/getting_started/photos/somewhere.jpg"
image="../cfdocs/images/artgallery/paul01.jpg">
<!--- The following code creates the first slide in the presentation
from HTML. --->
<cfpresentationslide title="Introduction" presenter="Jeff"
audio="myAudio1.mp3" duration="5">
<h3>Introduction</h3>
<table>
<tr><td>
<ul>
<li>Company Overview</li>
<li>Salary by Department</li>
<li>Employee Salary Details</li>
</ul>
</td></tr>
</table>
</cfpresentationslide>
<!--- The following code creates the second slide in the presentation.
The chart is populated with data from the database query. --->
<cfpresentationslide title="Salary by Department" presenter="Lori"
duration="5" audio="myAudio3.mp3">
<h3>Salary by Department</h3>
<cfchart format="jpg" xaxistitle="Department" yaxistitle="Salary">
<cfchartseries type="bar" query="GetSalaryDetails"
itemcolumn="Dept_Name" valuecolumn="salary">
</cfchartseries>
</cfchart>
</cfpresentationslide>
<!--- The following code creates the third slide in the presentation. The table is populated
with data from the query. The table also contains an image located relative to the CFM page on
1055
Example 2
The following example shows how to create a simple sales presentation with data from the cfartgallery database.
Specifically, it shows how to perform the following tasks:
1056
<!--- The following query extracts data from the cfartgallery database. --->
<cfquery name="artwork" datasource="cfartgallery">
SELECT FIRSTNAME || ' '|| LASTNAME AS FULLNAME, ARTISTS.ARTISTID, ARTNAME, PRICE, ISSOLD
FROM ARTISTS, ART
WHERE ARTISTS.ARTISTID = ART.ARTISTID
ORDER BY LASTNAME
</cfquery>
<!--- The following query of queries determines the total dollar amount of
sales per artist. --->
<cfquery dbtype="query" name="artistname">
SELECT FULLNAME,
SUM(PRICE) AS totalSale
FROM ARTWORK
WHERE ISSOLD = 1
GROUP BY FULLNAME
ORDER BY totalSale
</cfquery>
<!--- The following code determines the look of the slide presentation. ColdFusion displays
the slide presentation directly in the browser because no destination is specified. The title
appears above the presenter information. --->
<cfpresentation title="Art Sales Presentation" primaryColor="##0000FF" glowColor="##FF00FF"
lightColor="##FFFF00" showOutline="yes" showNotes="yes">
<!--- The following code defines the presenter information. You can assign each presenter
to one or more slides. --->
<cfpresenter name="Aiden" title="Artist" email="[email protected]"
image="../cfdocs/images/artgallery/aiden01.jpg">
<cfpresenter name="Raquel" title="Artist" email="[email protected]"
image="../cfdocs/images/artgallery/raquel05.jpg">
<cfpresenter name="Paul" title="Artist" email="[email protected]"
image="../cfdocs/images/artgallery/paul01.jpg">
<!--- The following code defines the content for the first slide in the presentation. The
duration of the slide determines how long the slide plays before proceeding to the next
slide. The audio plays for the duration of the slide. --->
<cfpresentationslide title="Introduction" presenter="Aiden" duration="5"
audio="myAudio1.mp3">
<h3>Introduction</h3>
<table>
<tr><td>
<ul>
<li>Art Sales Overview</li>
<li>Total Sales</li>
<li>Total Sales by Artist</li>
<li>Conclusion</li>
</ul>
</td>
<td><img src="../cfdocs/images/artgallery/maxwell01.jpg"/></td></tr>
</table>
</cfpresentationslide>
<!--- The following code generates the second slide in the presentation from an HTML file
located on an external website. --->
<cfpresentationslide title="Artwork Sales Overview" presenter="Raquel"
audio="myAudio2.mp3" duration="5" src="http://www.louvre.com/index.html"/>
1057
<!--- The following code generates the third slide in the presentation, which contains a
pie chart with data extracted from the initial database query. ColdFusion runs the video
defined in the cfpresentationslide tag in place of the presenter image defined in the
cfpresenter tag. --->
<cfpresentationslide title="Total Artwork Sold" presenter="Aiden"
duration="5" video="video1.flv">
<h3>Total Sales</h3>
<cfchart format="jpg" chartwidth="500" show3d="yes">
<cfchartseries type="pie" query="artwork"
colorlist="##00FFFF,##FF00FF" itemcolumn="issold"
valuecolumn="price"/>
</cfchart>
</cfpresentationslide>
<!--- The following code generates the fourth slide in the presentation with
data extracted from the query of queries. --->
<cfpresentationslide title="Sales by Artist" presenter="Paul"
duration="5" audio="myAudio3.mp3">
<h3>Total Sales by Artist</h3>
<table border cellspacing=10 cellpadding=0>
<TR>
<TD>
<table border cellspacing=0 cellpadding=5>
<tr>
<th>Artist Name</th>
<th>Total Sales</th>
</tr>
<tr>
<cfoutput query="artistname">
<td>#FULLNAME#</td>
<td>#dollarFormat(totalSale)#</td>
</tr>
</cfoutput>
</table>
</td>
<td>
<cfchart format="jpg" xaxistitle="Artist" yaxistitle="Total Sales"
chartwidth="400">
<cfchartseries type="bar" query="artistname"
itemcolumn="fullname" valuecolumn="totalSale"/>
</cfchart>
</td>
</tr>
</table>
</cfpresentationslide>
<!--- The following code defines the final slide in the presentation. This slide does not
have a presenter assigned to it. --->
<cfpresentationslide title="Conclusion" duration="1" notes="Special thanks to Lori and
Jeff for contributing their art and expertise.">
<h1>Great Job Team!</h1>
<p><img src="../cfdocs/images/artgallery/paul05.jpg"></p>
</cfpresentationslide>
</cfpresentation>
1058
1059
Basic view
The basic view of an XML document object presents the object as a container that holds one root element structure.
The root element can have any number of nested element structures. Each element structure represents an XML tag
(start tag/end tag set) and all its contents; it can contain additional element structures. A basic view of the simple XML
document looks like the following:
Document object
Element: last
Text:
Wilder
Element: name
Attributes: EmpType = Contract
Element: first
Text:
Laura
Element: last
Text:
Ingalls
1060
The following code displays this output. It assumes that you save the code in a file under your web root, such as
C:\Inetpub\wwwroot\testdocs\employeesimple.xml
<cffile action="read" file="C:\Inetpub\wwwroot\testdocs\employeesimple.xml"
variable="xmldoc">
<cfset mydoc = XmlParse(xmldoc)>
<cfdump var="#mydoc#">
1061
Entry name
Type
Description
XmlRoot
Element
XmlComment
String
A string made of the concatenation of all comments on the document, that is, comments in
the document prologue and epilog. This string does not include comments inside document
elements.
XmlDocType
XmlNode
The DocType attribute of the document. This entry only exists if the document specifies a
DocType. This value is read only; you cannot set it after the document object has been created
This entry does not appear when the cfdump tag displays an XML element structure.
Type
Description
XmlName
String
XmlNsPrefix
String
XmlNsURI
String
XmlText or
String
A string made of the concatenation of all text and CData text in the element, but not inside any
child elements. When you assign a value to the XmlCdata element, ColdFusion places the text
inside a CDATA information item. When you retrieve information from document object, these
element names return identical values.
XmlComment
String
A string made of the concatenation of all comments inside the XML element, but not inside
any child elements.
XmlAttributes
Structure
XmlChildren
Array
XmlParent
XmlNode
XmlCdata
This entry does not appear when the cfdump tag displays an XML element structure.
XmlNodes
Array
Type
Description
XmlName
String
The node name. For nodes such as Element or Attribute, the node name is the element or
attribute name.
XmlType
String
XmlValue
String
The node value. This entry is used only for Attribute, CDATA, Comment, and Text type nodes.
Note: The cfdump tag does not display XmlNode structures. If you try to dump an XmlNode structure, the cfdump tag
displays Empty Structure.
The following table lists the contents of the XmlName and XmlValue fields for each node type that is valid in the
XmlType entry. The node types correspond to the objects types in the XML DOM hierarchy.
1062
Node type
XmlName
xmlValue
CDATA
#cdata-section
COMMENT
#comment
ELEMENT
Tag name
Empty string
ENTITYREF
Empty string
PI (processing instruction)
Empty string
TEXT
#text
ENTITY
Entity name
Empty string
NOTATION
Notation name
Empty string
DOCUMENT
#document
Empty string
FRAGMENT
#document-fragment
Empty string
DOCTYPE
Empty string
Note: Although XML attributes are nodes on the DOM tree, ColdFusion does not expose them as XML DOM node data
structures. To view an elements attributes, use the element structures XMLAttributes structure.
The XML document object and all its elements are exposed as DOM node structures. For example, you can use the
following variable names to reference nodes in the DOM tree that you created from the XML example in A simple
XML document on page 1059:
mydoc.XmlName
mydoc.XmlValue
mydoc.XmlRoot.XmlName
mydoc.employee.XmlType
mydoc.employee.XmlNodes[1].XmlType
1063
Tag or function
Description
<cfxml variable="objectName"
Creates a ColdFusion XML document object consisting of the markup in the tag body. The tag can
include XML and CFML tags. ColdFusion processes all CFML in the tag body before converting the
resulting text to an XML document object.
[caseSensitive="Boolean"]>
If you specify the CaseSensitive="True" attribute, the case of names of elements and attributes
in the document is meaningful. The default value is False.
For more information on using the cfxml tag, see Creating an XML document object using the
cfxml tag on page 1067.
XmlParse (XMLText
[[, caseSensitive],
validator])
Converts an XML document in a file or a string variable into an XML document object, and optionally
validates the document against a DTD or schema.
If you specify the optional second argument as True, the case of names of elements and attributes
in the document is meaningful. The default value is False.
For more information on using the XmlParse function, see Creating an XML document object from
existing XML on page 1068.
XmlNew([caseSensitive])
XmlElemNew(objectName{,
namespaceURI],
Returns an XML document object element with the specified name, optionally belonging to the
specified namespace. You can omit the namespaceURI parameter and use only a namespace prefix
if the prefix is defined elsewhere in the object.
elementName)
For more information on using theXmlElemNew function, see Adding an element on page 1073.
XmlTransform(XMLVar,
XSLTStringVar[,
parameters])
For more information on using theXmlTransform function, see Transforming documents with XSLT
on page 1079.
XmlSearch(objectName,
Uses an XPath expression to search an XML document object and returns an array of XML elements
that match the search criteria.
XPathExpression)
For more information on using the XmlSearch function, see Extracting data with XPath on
page 1080.
XmlValidate(xmlDoc[,
validator])
XmlChildPos(element,
elementName, position)
Uses a Document Type Definition (DTD) or XML Schema to validate an XML text document (in a
string or file) or an XML document object. The validator can be a DTD or Schema. If you omit the
validator parameter, the document must specify a DTD or schema. For more information on
using the XmlValidate function, see Validating XML documents on page 1079
Returns the position (index) in an XmlChildren array of the Nth child with the specified element
name. For example, XmlChildPos(mydoc.employee, "name", 2) returns the position in
mydoc.employee.XmlChildren of the mydoc.employee.name[2] element. This index can be used in
the ArrayInsertAt and ArrayDeleteAt functions.
For more information on using theXmlChildPos function, see Determining the position of a child
element with a common name on page 1073, Adding an element on page 1073, and Deleting
elements on page 1075.
XmlGetNodeType(xmlNode)
Returns a string identifying the type of an XML document object node returned by the function or
in an elements XmlNodes array.
IsWDDX(String)
IsXML(String)
1064
Tag or function
Description
IsXmlAttribute(variable)
Determines whether the function parameter is an XML Document Object Model (DOM) attribute
node.
IsXmlDoc(objectName)
IsXmlElem(elementName)
IsXmlNode(variable)
IsXmlRoot(elementName)
Returns True if the function argument is the root element of an XML document object.
ToString(objectName)
XmlFormat(string)
Escapes special XML characters in a string so that the string can be used as text in XML.
By default, ColdFusion ignores element name case. As a result, it considers the element name MyElement and the
element name myELement to be equivalent. To make element name matching case-sensitive, specify
CaseSensitive="True" in the cfxml tag, or specify True as a second argument in the XmlParse or XmlNew
function that creates the document object.
If your XML object is case sensitive, do not use dot notation to reference an element or attribute name. Use the
name in associative array (bracket) notation, or a reference that does not use the case-sensitive name. For example,
do not use names such as the following:
1065
MyDoc.employee.name[1]
MyDoc.employee.XmlAttributes.Version
Important: Because ColdFusion always treats variable names as case-insensitive, using dot notation for element and
attribute names in a case-sensitive XML document can generate unexpected results (such as all-uppercase variable
names), exceptions, or both.
If your XML object is case sensitive, you cannot use dot notation to reference an element or attribute name. Use the
name in associative array (bracket) notation, or a reference that does not use the case-sensitive name (such as
XmlChildren[1]) instead.
Use an array index to specify one of multiple elements with the same name; for example,
#mydoc.employee.name[1] and #mydoc.employee.name[2].
If you omit the array index on the last component of an element identifier, ColdFusion treats the reference as the
array of all elements with the specified name. For example, mydoc.employee.name refers to an array of two name
elements.
Use an array index into the XmlChildren array to specify an element without using its name; for example,
mydoc.XmlRoot.XmlChildren[1].
Use associative array (bracket) notation to specify an element name that contains a period or colon; for example,
myotherdoc.XmlRoot["Type1.Case1"].
The following variables all reference the EmpType attribute of the first name element in the XML document created
in A simple XML document on page 1059:
mydoc.employee.name[1].XmlAttributes.EmpType
mydoc.employee.name[1].XmlAttributes["EmpType"]
mydoc.employee.XmlChildren[1].XmlAttributes.EmpType
mydoc.XmlRoot.name[1].XmlAttributes["EmpType"]
mydoc.XmlRoot.XmlChildren[1].XmlAttributes.EmpType
Neither of these lists contains a complete set of the possible combinations that can make up a reference to the value or
attribute.
1066
For example, the rules in Referencing the contents of an XML object on page 1064 apply to
mydoc.employee.name[1].first in the following expression:
mydoc.employee.name[1].first.MyNewElement = XmlElemNew(mydoc, NewElement);
The rule for naming in case correct document objects, however, applies to the full reference string, as indicated by the
following caution:
Important: Because ColdFusion always treats variable names as case-insensitive, using dot notation for element and
attribute names in a case-sensitive XML document can generate unexpected results (such as all-uppercase variable
names), exceptions, or both. In case-sensitive XML documents, use associative array notation or DOM notation names
(such as XmlRoot or XmlChldren[2]).
Referencing the last element on the left side of an expression
The following rules apply to the meaning of the last component on the left side of an expression:
1 The component name is an element structure key name (XML property name), such as XmlComment, ColdFusion
sets the value of the specified element structure entry to the value of the right side of the expression. For example,
the following line sets the XML comment in the mydoc.employee.name[1].first element to This is a comment:
mydoc.employee.name[1].first.XmlComment = "This is a comment";
2 If the component name specifies an element name and does not end with a numeric index, for example
mydoc.employee.name, ColdFusion assigns the value on the right of the expression to the first matching element.
For example, if both mydoc.employee.name[1] and mydoc.employee.name[2] exist, the following expression
replaces mydoc.employee.name[1] with a new element named address, not an element named name:
mydoc.employee.name = XmlElemNew(mydoc, "address");
After executing this line, if there had been both mydoc.employee.name[1] and mydoc.employee.name[2], now
only one mydoc.employee.name element exists with the contents of the original mydoc.employee.name[2].
3 If the component name does not match an existing element, the element names on the left and right sides of the
expression must match. ColdFusion creates an element with the name of the element on the left of the expression.
If the element names do not match, it generates an error.
For example if a, mydoc.employee.name.phoneNumber element does not exist, the following expression creates
an mydoc.employee.name.phoneNumber element:
mydoc.employee.name.phoneNumber = XmlElemNew(mydoc, "phoneNumber");
4 If the component name does not match an existing element and the components parent or parents also do not exist,
ColdFusion creates any parent nodes as specified on the left side and use the previous rule for the last element. For
example, no mydoc.employee.phoneNumber element exists, the following expression creates a phoneNumber
element containing an AreaCode element:
mydoc.employee.name.phoneNumber.AreaCode = XmlElemNew(mydoc, "AreaCode");
1067
When you retrieve data from the document object, references to XmlCdata and XmlText return the same string.
The following example shows how ColdFusion handles CDATA text:
<cfscript>
myCDATA = "This is CDATA text";
MyDoc = XmlNew();
MyDoc.xmlRoot = XmlElemNew(MyDoc,"myRoot");
MyDoc.myRoot.XmlChildren[1] = XmlElemNew(MyDoc,"myChildNodeCDATA");
MyDoc.myRoot.XmlChildren[1].XmlCData = "#myCDATA#";
</cfscript>
<h3>Assigning a value to MyDoc.myRoot.XmlChildren[1].XmlCdata.</h3>
<cfoutput>
The type of element MyDoc.myRoot.XmlChildren[1] is:
#MyDoc.myRoot.XmlChildren[1].XmlType#<br>
The value when output using XmlCdata is: #MyDoc.myRoot.XmlChildren[1].XmlCData#<br>
The value when output using XmlText is: #MyDoc.myRoot.XmlChildren[1].XmlText#<br>
</cfoutput>
<br>
The XML text representation of Mydoc is:
<cfoutput><XMP>#tostring(MyDoc)#</XMP></cfoutput>
<h3>Assigning a value to MyDoc.myRoot.XmlChildren[1].XmlText.</h3>
<cfset MyDoc.myRoot.XmlChildren[1].XmlText = "This is XML plain text">
<cfoutput>
The value when output using XmlCdata is: #MyDoc.myRoot.XmlChildren[1].XmlCData#<br>
The value when output using XmlText is: #MyDoc.myRoot.XmlChildren[1].XmlText#<br>
</cfoutput>
<br>
The XML text representation of Mydoc is:
<cfoutput><XMP>#tostring(MyDoc)#</XMP></cfoutput>
1068
This example creates a document object with a root element MyDoc, which includes text that displays the value of the
ColdFusion variable testVar. MyDoc has four nested child elements, which are generated by an indexed cfloop tag. The
cfdump tag displays the resulting XML document object.
Note: When you use the cfxml tag, do not include an <?xml ?> processing directive in the tag body. This directive is not
required, and causes an error. To process XML text that includes the <?xml ?> directive, use the XmlParse function.
1069
The following example converts an XML text document in a file to an XML document object:
<cfset myXMLDocument=XmlParse("C:\temp\myxmldoc.xml" variable="XMLFileText")>
The XmlParse function takes a second, optional, attribute that specifies whether to maintain the case of the elements
and attributes in the document object. The default is to have the document object be case-insensitive. For more
information on case sensitivity, see Referencing the contents of an XML object on page 1064.
The XmlParse function also lets you specify a DTD or Schema to validate the XML text; if the XML is not valid,
ColdFusion generates an error. You can specify the filename or URL of the validator, or the DTD or Schema can be in
a CFML variable. You can also tell ColdFusion to use a DTD or Schema that is identified in the XML text. If you specify
validation, also specify whether the document is case sensitive. The following example validates an XML document
on file using a DTD that it specifies using a URL:
myDoc=XMLParse("C:\CFusion\wwwroot\examples\custorder.xml", false,
"http://localhost:8500/examples/custorder.dtd")>
Use
ArrayLen
Determines the number of child elements in an element, that is, the number of elements in an elements
XmlChildren array.
ArrayIsEmpty
StructCount
StructIsEmpty
1070
Function
Use
StructKeyArray
Gets an array or list with the names of all of the attributes in an elements XmlAttributes structure. Returns
the names of the children of an XML element.
StructKeyList
ArrayInsertAt
ArrayAppend
ArrayPrepend
ArraySwap
ArraySet
Sets a range of entries in an XmlChildren array to equal the contents of a specified element structure. Each
entry in the array range is a copy of the structure. Can be used to set a single element by specifying the same
index as the beginning and end of the range.
ArrayDeleteAt
ArrayClear
StructDelete
StructClear
Duplicate
IsArray
Returns True for the XmlChildren array. Returns false if you specify an element name, such as
mydoc.XmlRoot.name, even if multiple name elements exist in XmlRoot.
IsStruct
Returns False for XML document objects, elements, and nodes. Returns True for XmlAttributes structures.
StructGet
Returns the specified structure, including XML document objects, elements, nodes, and XmlAttributes
structures.
StructAppend
Appends a document fragment XML document object to another XML document object.
StructInsert
StructUpdate
Sets or replaces the value of a document object property such as XmlName, or of a specified attribute in an
XmlAttributes structure.
Note: Array and structure functions not in the preceding or table or the table in the next section, do not work with XML
document objects, XML elements, or XML node structures.
1071
Array function
Result
IsArray(elemPath.elemName)
ArrayClear(elemPath.elemName)
Removes all the elements with name elemName from the elemPath element.
ArrayLen(elemPath.elemName)
ArrayDeleteAt(elemPath.elemName, n)
Deletes the nth child named elemName from the elemPath element.
ArrayIsEmpty(elemPath.elemName)
ArrayToList(elemPath.elemName, n)
Returns a comma-separated list of all the XmlText properties of all the children of
elemPath named elemName.
Using a function
Attribute
StructInsert(xmlElemPath.XmlAttributes, "key",
"value")
xmlElemPath.XmlAttributes.key ="value"
xmlElemPath.XmlAttributes["key"]="valu
e"
Child element
To append:
To append:
ArrayAppend(xmlElempath.XmlChildren,newElem)
xmlElemPath.XmlChildren[i] =newElem
To insert:
ArrayInsertAt(xmlElempath.XmlChildren,
position, newElem)
xmlElemPath.newChildName =newElem
1072
Type
Using a function
Property
StructDelete(xmlElemPath, propertyName)
xmlElemPath.propertyName=""
Attribute
All attributes:
Not available
StructDelete(xmlElemPath, XmlAttributes)
A specific attribute:
StructDelete(xmlElemPath.XmlAttributes,"attributeName")
Child element
Not available
StructDelete(xmlElemPath, "XmlChildren")
or
ArrayClear(xmlElemPath.XmlChildren)
A specific child:
ArrayDeleteAt(xmlElemPath.XmlChildren,position)
ArrayDeleteAt(xmlElemPath.elemName,position)
Using a function
Property
StructUpdate(xmlElemPath,"propert
yName", "value")
xmlElemPath.propertyName ="value"
xmlElemPath["propertyName"] ="value"
Attribute
StructUpdate(xmlElemPath.XmlAttri
butes,"attributeName", "value")
xmlElemPath.XmlAttributes.attributeName="value"
xmlElemPath.XmlAttributes["attributeName"] =
"value"
Child element
ArraySet(xmlElemPath.XmlChildren,
index,index, newElement)
(replace)
(use the same value for both index entries to
change one element)
parentElemPath["elementName"]= newElement
or
parentElemPath["elementName"][index] = newElement
1073
The following lines use this function to display the number of nodes named name in the mydoc.employee element:
<cfoutput>
Nodes Found: #NodeCount(mydoc.employee, "name")#
</cfoutput>
Adding an element
You can add an element by creating an element or by using an existing element.
Use the XmlElemNew function to create a new, empty element. This function has the following form:
XmlElemNew(docObject, elementName)
where docObject is the name of the XML document object in which you are creating the element, and elementName is
the name you are giving the new element.
Use an assignment statement with an existing element on the right side to create an element using an existing element.
See Copying an existing element on page 1075 for more information on adding elements using existing elements.
1074
The following line adds a new department element as the first element in employee. The name elements become the
second and third elements.
<cfset ArrayInsertAt(mydoc.employee.XmlChildren, 1, XmlElemNew(mydoc,
"department"))>
Use the format parentElement.XmlChildren to specify the array of elements to which you are adding the new
element. For example, the following line causes an error:
<cfset ArrayInsertAt(mydoc.employee.name, 2, XmlElemNew(mydoc, "PhoneNumber")>
If you have multiple child elements with the same name, and you want to insert a new element in a specific position,
use the function XmlChildPos to determine the location in the XmlChildren array where you want to insert the new
element. For example, the following code determines the location of mydoc.employee.name[1] and inserts a new name
element as the second name element:
<cfscript>
nameIndex = XmlChildPos(mydoc.employee, "name", 1);
ArrayInsertAt(mydoc.employee.XmlChildren, nameIndex + 1, XmlElemNew(mydoc,
"name"));
</cfscript>
Using a namespace: When you use a function to add an element, you can assign the element to a namespace by
including the namespace prefix in the element name. If you have not yet associated the prefix with a namespace URI,
also include a parameter with the namespace URI in the XmlElemNew function. This parameter must be the second
parameter in the method, and the element name must be the third parameter. ColdFusion then associates the
namespace prefix with the URI, and you can omit the URI parameter in further xmlElemNew functions.
The following example adds two to the supplies document root two elements in the Prod namespace. The first
XmlElemNew function use sets the association between the Prod namespace prefix and the URI; the second use only
requires the prefix on the element name.
<cfscript>
mydoc.supplies.XmlChildren[1] = XmlElemNew(mydoc,
"http://www.foo.com/Products", "Prod:soap");
mydoc.supplies.XmlChildren[2] = XmlElemNew(mydoc, "Prod:shampoo");
</cfscript>
1075
If the parent element does not have any children with the same name as the new child, you can specify the name of the
new node or the left side of the assignment. For example, the following line appends a phoneNumber element to the
children of the first name element in mydoc.employee:
<cfset mydoc.employee.name[1].phoneNumber = XmlElemNew(mydoc, "phoneNumber")>
You cannot use the node name on the left to add an element with the same name as an existing element in the parent.
For example, if mydoc.employee has two name nodes, the following line causes an error:
<cfset mydoc.employee.name[3] = XmlElemNew(mydoc, "name")>
When you copy an element, the new element must have the same name as the existing element. If you specify the new
element by name on the left side of an assignment, the element name must be the same as the name on the right side.
For example, the following expression causes an error:
<cfset mydoc.employee.name[2].telephone = mydoc.employee.name[1].phoneNumber>
Deleting elements
You can use many methods to delete individual or multiple elements.
Deleting individual elements
Use the ArrayDeleteAt function to delete a specific element from an XML document object. For example, the
following line deletes the second child element in the mydoc.employee element:
<cfset ArrayDeleteAt(mydoc.employee.XmlChildren, 2)>
If an element has only one child element with a specific name, you can also use the StructDelete function to delete
the child element. For example, the following line deletes the phoneNumber element named in the second
employee.name element:
<cfset StructDelete(mydoc.employee.name[2], "phoneNumber")>
When multiple child elements have the same name, specify the element position, either among the elements of the
same name, or among all child elements. Fore example, you can use the following line to delete the second name
element in mydoc.employee:
<cfset ArrayDeleteAt(mydoc.employee.name, 2)>
You can also determine the position in the XmlChildren array of the element you want to delete and use that position.
To do so, use the XmlChildPos function. For example, the following lines determine the location of
mydoc.employee.name[2] and delete the element:
<cfset idx = XmlChildPos(mydoc.employee, "name", 2)>
<cfset ArrayDeleteAt(mydoc.employee.XmlChildren, idx)>
1076
Use the StructDelete or ArrayClear function with XmlChildren to delete all of an elements child elements. For
example, each of the following lines deletes all child elements of the mydoc.employee.name[2] element:
<cfset StructDelete(mydoc.employee.name[2], "XmlChildren")>
<cfset ArrayClear(mydoc.employee.name[2].XmlChildren)>
1077
To replace an element with a copy of an existing element, use the existing element on the right side of an expression.
For example, the following line replaces the phoneNumber element for mydoc.employee.name[2] with the
phoneNumber element from mydoc.employee.name[1]:
<cfset mydoc.employee.name[2].phoneNumber=mydoc.employee.name[1].phoneNumber>
Note: You cannot copy or move an element from one document object to another document object.
1078
<!--- Read the file and convert it to an XML document object --->
<cffile action="read" file="C:\CFusion\wwwroot\myexamples\employees.xml" variable="myxml">
<cfset mydoc = XmlParse(myxml)>
<!--- get an array of employees --->
<cfset emp = mydoc.employee.XmlChildren>
<cfset size = ArrayLen(emp)>
<cfoutput>
Number of employees = #size#
<br>
</cfoutput>
<br>
<!--- create a query object with the employee data --->
<cfset myquery = QueryNew("fname, lname") >
<cfset temp = QueryAddRow(myquery, #size#)>
<cfloop index="i" from = "1" to = #size#>
<cfset temp = QuerySetCell(myquery, "fname",
#mydoc.employee.name[i].first.XmlText#, #i#)>
<cfset temp = QuerySetCell(myquery, "lname",
#mydoc.employee.name[i].last.XmlText#, #i#)>
</cfloop>
<!--- Dump the query object --->
Contents of the myquery Query object: <br>
<cfdump var=#myquery#>
<br><br>
<!--- Select entries with the last name starting with A and dump the result --->
<cfquery name="ImqTest" dbType="query">
SELECT lname, fname
FROM myquery
WHERE lname LIKE 'A%'
</cfquery>
<cfdump var=#imqtest#>
1079
<!--- Query the database and get the names in the employee table --->
<cfquery name="myQuery" datasource="cfdocexamples">
SELECT FirstName, LastName
FROM employee
</cfquery>
<!--- Create an XML document object containing the data --->
<cfxml variable="mydoc">
<employee>
<cfoutput query="myQuery">
<name>
<first>#FirstName#</first>
<last>#LastName#</last>
</name>
</cfoutput>
</employee>
</cfxml>
<!--- dump the resulting XML document object --->
<cfdump var=#mydoc#>
<!--- Write the XML to a file --->
\\x
output=#toString(mydoc)#>
The XmlParse function can validate XML text that it is parsing against a DTD or Schema. It the function
encounters a validation error, ColdFusion generates an error and stops parsing the text. If the validator generates
warnings, but no errors, ColdFusion parses the document and returns the result.
The XmlValidate function can validate an XML text document or XML document object. against a DTD or
Schema. The function returns a data structure with detailed information from the validator, including arrays of
warning, error, and fatal error messages, and a Boolean status variable indicating whether the document is valid.
Your application can examine the status information and determine how to handle it further.
For examples of XML validation, see XmlParse and XmlValidate in the CFML Reference. The XmlParse example
validates a document using a DTD. The XmlValidate example validates the document using an XML Schema that
represents the same document structure as the DTD.
1080
2 Uses the style sheet to transform the mydoc XML document object.
3 Saves the resulting transformed document in a second file.
<cffile action="read" file="C:\CFusion\wwwroot\testdocs\simpletransform.xsl"
variable="xslDoc">
<cfset transformedXML = XmlTransform(mydoc, xslDoc)>
<cffile action="write" file="C:\CFusion\wwwroot\testdocs\transformeddoc.xml"
output=transformedXML>
XSL and XSLT are specified by the World Wide Web Consortium (W3C). For detailed information on XSL, XSLT, and
XSL style sheets, see the W3C website at www.w3.org/Style/XSL/. Several books are available on using XSL and XSLT.
XPath is specified by the World Wide Web Consortium. For detailed information on XPath, see the W3C website at
www.w3.org/TR/xpath. Most books that cover XSLT also discuss XPath.
1081
This example displays the results of the processing steps to show you what has been done.
The XML document
The order.xml document has the following structure:
The root element is named order and has one attribute, id.
One customer element exists with firstname, lastname, and accountnum attributes. The customer element does not
have a body
1082
1083
1084
Code
Description
<cffile action="read"
file="C:\CFusion\wwwroot\examples\order.xml"
variable="myxml">
<cfset mydoc = XmlParse(myxml)>
<!--- Extract account number --->
<cfset
accountNum=#mydoc.order.customer.XmlAttributes.acc
ountNum#>
Reads the XML from a file and convert it to an XML document object.
#mydoc.order.items.item[i].XmlAttributes.id#,#i#)>
<cfset temp = QuerySetCell(orderquery, "name",
#mydoc.order.items.item[i].name.XmlText#, #i#)>
<cfset temp = QuerySetCell(orderquery, "qty",
#mydoc.order.items.item[i].quantity.XmlText#,
#i#)>
<cfset temp = QuerySetCell(orderquery,
"unitPrice",
#mydoc.order.items.item[i].unitprice.XmlText#,
#i#)>
</cfloop>
Creates a query with columns for the item_id, name, qty, and unitPrice
values for each item.
For each XML item entry in the mydoc.order.items entry, fills one row
of the query with the items id attribute and the text in the name,
quantity, and unitprice entries that it contains.
<cfquery name="discountQuery"
datasource="cfdocexamples">
SELECT *
FROM employee
WHERE Emp_Id = #accountNum#
</cfquery>
<cfset drate = 0>
<cfif #discountQuery.RecordCount# is 1>
<cfset drate = 10>
</cfif>
Uses a query of queries with the SUM operator to calculate the total
cost before discount of the ordered items, then applies the discount to
the price. The result of the query is a single value, the total price.
<cfxml variable="receiptxml">
<receipt num = "34">
<cfoutput>
<price>#discountPrice#</price>
<cfif drate GT 0 >
<discountRate>#drate#</discountRate>
</cfif>
</cfoutput>
<itemsFilled>
<cfoutput query="orderQuery">
<name>#name# </name>
<qty> #qty# </qty>
<price> #qty*unitPrice# </price>
</cfoutput>
</itemsFilled>
</receipt>
</cfxml>
1085
The WDDX XML vocabulary consists of a document type definition (DTD) that describes the structure of standard
data types and a set of components for each of the target platforms to do the following:
Serialize: The data from its native representation into a WDDX XML document or document fragment.
Deserialize: A WDDX XML document or document fragment into the native data representation, such as a CFML
structure.
This vocabulary creates a way to move data, its associated data types, and descriptors that allow the data to be
manipulated on a target system, between arbitrary application servers.
Note: The WDDX DTD, which includes documentation, is located at
www.openwddx.org/downloads/dtd/wddx_dtd_10.txt.
WDDX is a valuable tool for ColdFusion developers, however, its usefulness is not limited to CFML. If you serialize a
common programming data structure (such as an array, recordset, or structure) into WDDX format, you can use
HTTP to transfer the data across a range of languages and platforms. Also, you can use WDDX to store complex data
in a database, file, or even a client variable.
WDDX has two features that make it useful for transferring data in a web environment:
It is lightweight. The JavaScript used to serialize and deserialize data, including a debugging function to dump
WDDX data, occupies less than 22 K.
Unlike traditional client-server approaches, the source and target system can have minimal-to-no prior knowledge
of each other. They only must know the structure of the data that is being transferred.
WDDX was created in 1998, and many applications now expose WDDX capabilities. The best source of information
about WDDX is www.openwddx.org. This site offers free downloads of the WDDX DTD and SDK and additional
resources, including a WDDX FAQ, a developer forum, and links to additional sites that provide WDDX resources.
Uses of WDDX
WDDX is useful for transferring complex data between applications. For example, you can use it to exchange data
between a CFML application and a CGI or PHP application. WDDX is also useful for transferring data between the
server and client-side JavaScript.
Exchanging data across application servers
WDDX is useful for the transfer of complex, structured data seamlessly between different application server platforms.
For example, an application based on ColdFusion at one business could cfwddx use to convert a purchase order
structure to WDDX. It could then use cfhttp to send the WDDX to a supplier running a CGI-based system.
The supplier could then deserialize the WDDX to its native data form, the extract information from the order, and pass
it to a shipping company running an application based on ASP.
Transferring data between the server and browser
You can use WDDX for server-to-browser and browser-to-server data exchanges. You can transfer server data to the
browser in WDDX format and convert it to JavaScript objects on the browser. Similarly, your application pages can
serialize JavaScript data generated on the browser into WDDX format and transfer the data to the application server.
You then deserialize the WDDX XML into CFML data on the server.
On the server, you use the cfwddx tag to serialize and deserialize WDDX data. On the browser, you use WddxSerializer
and WddxRecordset JavaScript utility classes to serialize the JavaScript data to WDDX. (ColdFusion installs these
utility classes on your server as webroot/CFIDE/scripts/wddx.js.)
1086
When you deserialize this XML into CFML or JavaScript, the result is a structure that is created by either of the
following scripts:
JavaScript
CFScript
x = new Object();
x = structNew();
Conversely, when you serialize the variable x produced by either of these scripts into WDDX, you generate the XML
listed in the preceding code.
ColdFusion provides a tag and JavaScript objects that convert between CFML, WDDX, and JavaScript. Serializers and
deserializers for other data formats are available on the web. For more information, see www.openwddx.org.
Note: The cfwddx tag and the wddx.js JavaScript functions use UTF-8 encoding to represent data. Any tools that
deserialize ColdFusion-generated WDDX must accept UTF-8 encoded characters. UTF-8 encoding is identical to the
ASCII and ISO 8859 single-byte encodings for the standard 128 "7-bit" ASCII characters. However, UTF-8 uses a twobyte representation for "high-ASCII" ISO 8859 characters where the initial bit is 1.
WDDX data type support
The following text describes the data types that WDDX supports. This information is a distillation of the description
in the WDDX DTD. For more detailed information, see the DTD at www.openwddx.org.
1087
Description
Null
Null values in WDDX are not associated with a type such as number or string. The tag converts WDDX Nulls to
empty strings.
Numbers
WDDX documents use floating-point numbers to represent all numbers. The range of numbers is restricted to
+/-1.7E+/-308. The precision is restricted to 15 digits after the decimal point.
Date-time values
Date-time values are encoded according to the full form of ISO8601; for example, 2002-9-15T09:05:32+4:0.
Strings
Strings can be of arbitrary length and must not contain embedded nulls. Strings can be encoded using doublebyte characters.
Description
Array
Arrays are integer-indexed collections of objects of arbitrary type. Because most languages start array indexes at 0,
while CFML array indexes start at 1, working with array indexes can lead to nonportable data.
Structure
Structures are string-indexed collections of objects of arbitrary type, sometimes called associative arrays. Because
some of the languages supported by WDDX are not case-sensitive, no two variable names in a structure can differ only
in their case.
Recordset
Recordsets are tabular rows of named fields, corresponding to ColdFusion query objects. Only simple data types can
be stored in recordsets. Because some of the languages supported by WDDX are not case-sensitive, no two field names
in a recordset can differ only in their case. Field names must satisfy the regular expression [_A-Za-z][_.0-9A-Za-z]*
where the period (.) stands for a literal period character, not any character.
Binary
The binary data type represents strings (blobs) of binary data. The data is encoded in MIME base64 format.
CFML
XML
Java
Schema
ECMAScript/
COM
JavaScript
null
N/A
N/A
null
null
VT_NULL
boolean
Boolean
boolean
java.lang.Boolean
boolean
VT_BOOL
number
Number
number
java.lang.Double
number
VT_R8
dateTime
DateTime
dateTime
java.lang.Date
Date
VT_DATE
string
String
string
java.lang.String
string
VT_BSTR
array
Array
N/A
java.lang.Vector
Array
VT_ARRAY | VT_VARIANT
1088
WDDX
CFML
XML
Java
Schema
struct
Structure
ECMAScript/
COM
JavaScript
N/A
java.lang.
Object
IWDDXStruct
Hashtable
recordset
Query object
N/A
coldfusion.runtime.
QueryTable
WddxRecordset
IWDDXRecordset
binary
Binary
binary
byte[]
WddxBinary
V_ARRAY | UI1
Using WDDX
ColdFusion provides several tools for creating and converting WDDX that you can use for common application uses.
To
CFML
WDDX
CFML
JavaScript
WDDX
CFML
WDDX
JavaScript
A typical cfwddx tag used to convert a CFML query object to WDDX looks like the following:
<cfwddx action="cfml2wddx" input="#MyQueryObject#" output="WddxTextVariable">
In this example, MyQueryObject is the name of the query object variable, and WddxTextVariable is the name of the
variable in which to store the resulting WDDX XML.
Note: For more information on thecfwddx tag, see the CFML Reference.
1089
Note: To see how cfwddx Action="cfml2js" works, save this code under your web root directory, for example in
wwwroot/myapps/wddxjavascript.cfm, run the page in your browser and select View Source in your browser.
1090
The resulting WDDX packet appears in the WDDX packet display box. This step is intended only for test purposes.
Real applications handle the serialization automatically.
7 Click Submit to submit the data.
The WDDX packet is transferred to the server-side processing code, which deserializes it and displays the
information.
<!--- load the wddx.js file --->
<script type="text/javascript" src="/CFIDE/scripts/wddx.js"></script>
<!--- Data binding code --->
<script>
// Generic serialization to a form field
function serializeData(data, formField) {
wddxSerializer = new WddxSerializer();
wddxPacket = wddxSerializer.serialize(data);
if (wddxPacket != null) {
formField.value = wddxPacket;
}
else {
alert("Couldn't serialize data");
}
}
// Person info recordset with columns firstName and lastName
// Make sure the case of field names is preserved
var personInfo = new WddxRecordset(new Array("firstName", "lastName"), true);
// Add next record to end of personInfo recordset
function doNext() {
// Extract data
var firstName = document.personForm.firstName.value;
var lastName = document.personForm.lastName.value;
// Add names to recordset
nRows = personInfo.getRowCount();
personInfo.firstName[nRows] = firstName;
1091
personInfo.lastName[nRows] = lastName;
// Clear input fields
document.personForm.firstName.value = "";
document.personForm.lastName.value = "";
// Show added names on list
// This gets a little tricky because of browser differences
var newName = firstName + " " + lastName;
if (navigator.appVersion.indexOf("MSIE") == -1) {
document.personForm.names[length] =
new Option(newName, "", false, false);
}
else {
// IE version
var entry = document.createElement("OPTION");
entry.text = newName;
document.personForm.names.add(entry);
}
}
</script>
<!--- Data collection form --->
<form action="#cgi.script_name#" method="Post" name="personForm">
<!--- Input fields --->
Personal information<br>
First name: <input type=text name=firstName><br>
Last name: <input type=text name=lastName><br>
<br>
<!--- Navigation & submission bar --->
<input type="button" value="Next" onclick="doNext()">
<input type="button" value="Serialize"
onclick="serializeData(personInfo, document.personForm.wddxPacket)">
<input type="submit" value="Submit">
<br><br>
Names added so far:<br>
<select name="names" size="5">
</select>
<br>
<!--- The WDDX packet is stored here.--->
<!--- In a real application this text area would be a hidden
input field. --->
<br>
WDDX packet display:<br>
<textarea name="wddxPacket" rows="10" cols="80" wrap="Virtual">
</textarea>
</form>
1092
<b>Server-side processing</b><br>
<br>
<cfif isdefined("form.wddxPacket")>
<cfif form.wddxPacket neq "">
<!--- Deserialize the WDDX data --->
<cfwddx action="wddx2cfml" input=#form.wddxPacket#
output="personInfo">
<!--- Display the query --->
The submitted personal information is:<br>
<cfoutput query=personInfo>
Person #CurrentRow#: #firstName# #lastName#<br>
</cfoutput>
<cfelse>
The client did not send a well-formed WDDX data packet!
</cfif>
<cfelse>
No WDDX data to process at this time.
</cfif>
1093
Web services
Since its inception, the Internet has allowed people to access content stored on remote computers. This content can be
static, such as a document represented by an HTML file, or dynamic, such as content returned from a ColdFusion page
or CGI script.
Web services let you access application functionality that someone created and made available on a remote computer.
With a web service, you can make a request to the remote application to perform an action.
For example, you can request a stock quote, pass a text string for translation, or request information from a product
catalog. The advantage of web services is that you do not have to re-create application logic that someone else has
already created and, therefore, you can build your applications faster.
1094
Referencing a remote web service within your ColdFusion application is called consuming web services. Since web
services adhere to a standard interface regardless of implementation technology, you can consume a web service
implemented as part of a ColdFusion application, or as part of a .NET or Java application.
You can also create your own web services and make them available to others for remote access, called publishing web
service. Applications that consume your web service can be implemented in ColdFusion or by any application that
recognizes the web service standard.
A web service makes its associated WSDL file available over the Internet. You must know the URL of the WSDL
file defining the service. For example, you can access the WSDL file for the TemperatureService web service at the
following URL:
www.xmethods.net/sd/2001/TemperatureService.wsdl
For an overview of WSDL syntax, see Working with WSDL files on page 1095.
2 Make a request to the web service.
The following example runs an operation on the Temperature web service to retrieve the temperature in ZIP code
55987:
<cfinvoke
webservice="http://www.xmethods.net/sd/2001/TemperatureService.wsdl"
method="getTemp"
returnvariable="aTemp">
<cfinvokeargument name="zipcode" value="55987"/>
</cfinvoke>
<cfoutput>The temperature at ZIP code 55987 is #aTemp#</cfoutput>
For more information on consuming web services, see Consuming web services on page 1098.
1095
1096
After the web service is defined to Dreamweaver, you can drag it onto a page to call it using the cfinvoke tag.
For more information on using Dreamweaver, see its online Help system.
Note: The Web Services option is not available if you are running Dreamweaver on the Macintosh. However, you can
still use web services by writing code manually.
1097
<?xml version="1.0"?>
<definitions name="TemperatureService"
targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl"xmlns:tns="http://www.xm
ethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getTempRequest">
<part name="zipcode" type="xsd:string"/>
</message>
<message name="getTempResponse">
<part name="return" type="xsd:float"/>
</message>
<portType name="TemperaturePortType">
<operation name="getTemp">
<input message="tns:getTempRequest"/>
<output message="tns:getTempResponse"/>
</operation>
</portType>
<binding name="TemperatureBinding" type="tns:TemperaturePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getTemp">
<soap:operation soapAction=""/>
<input>
<soap:body use="encoded" namespace="urn:xmethods-Temperature"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-Temperature"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="TemperatureService">
<documentation>Returns current temperature in a given U.S. zipcode</documentation>
<port name="TemperaturePort" binding="tns:TemperatureBinding">
<soap:address
location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/>
</port>
</service>
</definitions>
Definition
definitions
The root element of the WSDL file. This area contains namespace definitions that you use to avoid naming
conflicts between multiple web services.
types
message
Defines the data transferred by a web service operation, typically the name and data type of input parameters
and return values.
port type
operation
input
output
Specifies the return values from the operation using a previously defined message.
1098
Component
Definition
fault
(not shown) Optionally specifies an error message returned from the operation.
binding
Specifies the protocol used to access a web service including SOAP, HTTP GET and POST, and MIME.
service
port
For additional descriptions of the contents of this WSDL file, see Consuming web services on page 1098.
CFML operator
Description
CFScript
()
CFML tag
CFML tag
One important consideration is that all consumption methods use the same underlying technology and offer the same
performance.
1099
The operation name used in the examples is getTemp. This operation takes a single input parameter defined as a
message of type getTempRequest.
You can see that the message element named getTempRequest contains one string parameter: zipcode. When you call
the getTemp operation, you pass the parameter as input.
The operation getTemp returns a message of type getTempResponse. The message statement in the WSDL file defines
the getTempResponse message as containing a single string parameter named return.
You can omit a parameter by setting the omit attribute to "yes". If the WSDL specifies that the argument is nullable,
ColdFusion sets the associated argument to null. If the WSDL specifies minoccurs=0, ColdFusion omits the argument
from the WSDL. However, CFC web services must still specify required="true" for all arguments.
1100
You can also use an attribute collection to pass parameters. An attribute collections is a structure where each structure
key corresponds to a parameter name and each structure value is the parameter value passed for the corresponding
key. The following example shows an invocation of a web service using an attribute collection:
<cfscript>
stArgs = structNew();
stArgs.zipcode = "55987";
</cfscript>
<cfinvoke
webservice="http://www.xmethods.net/sd/2001/TemperatureService.wsdl"
method="getTemp"
argumentcollection="#stArgs#"
returnvariable="aTemp">
<cfoutput>The temperature at ZIP code 55987 is #aTemp#</cfoutput>
In this example, you create the structure in a CFScript block, but you can use any ColdFusion method to create the
structure.
You can handle return values from web services by writing them to a variable, as the following example shows:
resultVar = webServiceName.operationName(inputVal1, inputVal2, ... );
Or, you can pass the return values directly to a function, such as the WriteOutput function, as the following example
shows:
writeoutput(webServiceName.operationName(inputVal1, inputVal2, ...) );
You can also use named parameters to pass information to a web service. The following example performs the same
operation as the preceding code, except that it uses named parameters to make the web service request:
1101
<cfscript>
ws = CreateObject("webservice",
"http://www.xmethods.net/sd/2001/TemperatureService.wsdl");
xlatstring = ws.getTemp(zipcode = "55987");
writeoutput("The temperature at 55987 is " & xlatstring);
</cfscript>
The WSDL file for the TemperatureService web service is compatible with ColdFusion because it uses rpc as the
binding style, and encoding as the encodingStyle.
1102
<cftry>
Place your application code here ...
<cfcatch type="application">
<!--- Add exception processing code here ... --->
</cfcatch>
...
<cfcatch type="Any">
<!--- Add exception processing code appropriate for all other
exceptions here ... --->
</cfcatch>
</cftry>
For more information on error handling, see Handling Errors on page 275.
Even though this web service takes as input the value of S, because you pass it as an inout parameter, you do not enclose
it in number signs.
Note: ColdFusion supports the use of inout and out parameters to consume web services. However, ColdFusion does not
support inout and out parameters when creating web services for publication.
If you register the TemperatureService web service in the Administrator using (for example, the name wsTemp), you
can then reference the web service as follows:
<cfscript>
ws = CreateObject("webservice", "wsTemp");
xlatstring = ws.getTemp("55987");
writeoutput("wsTemp: " & xlatstring);
</cfscript>
1103
Not only does registering the service in the Administrator enable you to shorten your code, it lets you change a web
service URL without modifying your code. So, if the TemperatureService web service moves to a new location, you only
update the administrator setting, not your application code.
For more information, see the ColdFusion Administrator online Help.
As part of consuming web services, understand how ColdFusion converts WSDL defined data types to ColdFusion
data types. The following table shows this conversion:
ColdFusion data type
numeric
SOAP-ENC:double
Boolean
SOAP-ENC:boolean
string
SOAP-ENC:string
array
SOAP-ENC:Array
binary
xsd:base64Binary
numeric
xsd:float
string
xsd:enumeration
date
xsd:dateTime
complex type
query
For many of the most common data types, such as string and numeric, a WSDL data type maps directly to a
ColdFusion data type. For complex WSDL data types, the mapping is not as straight forward. In many cases, you map
a complex WSDL data type to a ColdFusion structure. For more information on handling complex data types, see
Handling complex data types on page 1115.
1104
Note: For a list of how ColdFusion data types map to WSDL data types, see Data conversions between ColdFusion and
WSDL data types on page 1103.
The following example shows a ColdFusion component that takes a query as input and echoes the query back to the
caller:
<cfcomponent>
<cffunction name='echoQuery' returnType='query' access='remote'>
<cfargument name='input' type='query'>
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>
In the WSDL file for the echotypes.cfc component, you see the following definitions that specify the type of the
function input and output as QueryBean:
<wsdl:message name="echoQueryResponse">
<wsdl:part name="echoQueryReturn" type="tns1:QueryBean"/>
</wsdl:message>
<wsdl:message name="echoQueryRequest">
<wsdl:part name="input" type="tns1:QueryBean"/>
</wsdl:message>
For information on displaying WSDL, see Producing WSDL files on page 1106.
Since ColdFusion automatically handles mappings to ColdFusion data types, you can call this web service as the
following example shows:
<head>
<title>Passing queries to web services</title>
</head>
<body>
<cfquery name="GetEmployees" datasource="cfdocexamples">
SELECT FirstName, LastName, Salary
FROM Employee
</cfquery>
<cfinvoke
webservice = "http://localhost/echotypes.cfc?wsdl"
method = "echoQuery"
input="#GetEmployees#"
returnVariable = "returnedQuery">
<cfoutput>
Is returned result a query? #isQuery(returnedQuery)# <br><br>
</cfoutput>
<cfoutput query="returnedQuery">
#FirstName#, #LastName#, #Salary#<br>
</cfoutput>
</body>
1105
The function, named echoString, echoes back any string passed to it. To publish the function as a web service, modify
the function definition to add the access attribute and specify remote, as the following example shows:
<cffunction name="echoString" returnType="string" output="no" access="remote">
By defining the function as remote, ColdFusion includes the function in the WSDL file. Only those functions marked
as remote are accessible as a web service.
The following list defines the requirements for how to create web services for publication:
1 The value of the access attribute of the cffunction tag must be remote.
2 The cffunction tag must include the returnType attribute to specify a return type.
3 The output attribute of the cffunction tag must be set to No because ColdFusion converts all output to XML to
as required.
As part of publishing the component for access as a web service, ColdFusion generates the WSDL file that defines the
component where the WSDL file includes definitions for how ColdFusion data types map to WSDL data types. The
following table shows this mapping:
ColdFusion data type
numeric
SOAP-ENC:double
Boolean
SOAP-ENC:boolean
string
SOAP-ENC:string
array
SOAP-ENC:Array
1106
binary
xsd:base64Binary
date
xsd:dateTime
guid
SOAP-ENC:string
uuid
SOAP-ENC:string
Map
query
QueryBean
any
complex type
component definition
complex type
In most cases, consumers of ColdFusion web services can easily pass data to and return results from component
functions by mapping their data types to the WSDL data types shown in the preceding table.
Note: Document-literal web services use XML schema data types, not SOAP-ENC data types. For more information, see
Publishing document-literal style web services on page 1110.
For ColdFusion structures and queries, Some clients must process their data to map it to the correct type. For more
information, see Publishing web services that use complex data types on page 1119.
You can also define a data type in one ColdFusion component based on another component definition. For more
information on using components to specify a data type, see Using ColdFusion components to define data types for
web services on page 1109.
The cfcomponent tag includes optional attributes that you can use to control the WSDL that ColdFusion generates.
You can use these attributes to create meaningful WSDL attribute names, as the following example shows:
<cfcomponent style="document"
namespace = "http://www.mycompany.com/"
serviceportname = "RestrictedEmpInfo"
porttypename = "RestrictedEmpInfo"
bindingname = "myns:RestrictedEmpInfo"
displayname = "RestrictedEmpInfo"
hint = "RestrictedEmpInfo">
For complete control of the WSDL, advanced users can specify the cfcomponentwsdlFile attribute to use a
predefined WSDL file.
The following example defines a ColdFusion component that can be invoked as a web service:
1107
<cfcomponent>
<cffunction
name = "echoString"
returnType = "string"
output = "no"
access = "remote">
<cfargument name = "input" type = "string">
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>
If you register the component in Dreamweaver, it appears in the Components tab of the Application panel.
Requesting the WSDL file in a browser returns the following:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://ws"
xmlns:intf="http://ws"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns1="http://rpc.xml.coldfusion"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by ColdFusion -->
<wsdl:types>
<schema targetNamespace="http://rpc.xml.coldfusion"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="CFCInvocationException">
<sequence/>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="CFCInvocationException">
<wsdl:part name="fault" type="tns1:CFCInvocationException"/>
</wsdl:message>
<wsdl:message name="echoStringResponse">
<wsdl:part name="echoStringReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="echoStringRequest">
<wsdl:part name="input" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="echo">
<wsdl:operation name="echoString" parameterOrder="input">
<wsdl:input message="impl:echoStringRequest" name="echoStringRequest"/>
<wsdl:output message="impl:echoStringResponse"
name="echoStringResponse"/>
<wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="echo.cfcSoapBinding" type="impl:echo">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/
http"/>
1108
<wsdl:operation name="echoString">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="echoStringRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" namespace="http://ws" use="encoded"/>
</wsdl:input>
<wsdl:output name="echoStringResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" namespace="http://ws" use="encoded"/>
</wsdl:output>
<wsdl:fault name="CFCInvocationException">
<wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/
encoding/" name="CFCInvocationException" namespace=
"http://ws" use="encoded"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="echoService">
<wsdl:port binding="impl:echo.cfcSoapBinding" name="echo.cfc">
<wsdlsoap:address location="http://localhost:8500/ws/echo.cfc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
You can also invoke the web service using the following code:
1109
<cfscript>
ws = CreateObject("webservice", "http://localhost/echo.cfc?wsdl");
wsresults = ws.echoString("hello");
writeoutput(wsresults);
</cfscript>
name="AddrNumber" type="numeric">
name="Street" type="string">
name="City" type="string">
name="State" type="string">
name="Country" type="string">
The following code defines a component in the filename.cfc that defines first and last name properties:
<cfcomponent>
<cfproperty name="Firstname" type="string">
<cfproperty name="Lastname" type="string">
</cfcomponent>
You can then use address and name to define data types in a ColdFusion component created to publish a web service,
as the following example shows:
<cfcomponent>
<cffunction
name="echoName" returnType="name" access="remote" output="false">
<cfargument name="input" type="name">
<cfreturn #arguments.input#>
</cffunction>
<cffunction
name="echoAddress" returnType="address" access="remote" output="false">
<cfargument name="input" type="address">
<cfreturn #arguments.input#>
</cffunction>
</cfcomponent>
Note: If the component files are not in a directory under your web root, create a web server mapping to the directory that
contains them. You cannot use ColdFusion mappings to access web services.
The WSDL file for the web service contains data definitions for the complex types name and address. Each definition
consists of the elements that define the type as specified in the ColdFusion component file for that type. For example,
the following example shows the definition for name:
<complexType name="name">
<sequence>
<element name="firstname" nillable="true" type="soapenc:string"/>
<element name="lastname" nillable="true" type="soapenc:string"/>
</sequence>
</complexType>
You can also specify an array of CFCs in the returnType attribute, as the following example shows:
1110
<cfcomponent>
<cffunction
name="allNames" returnType="name[]" access="remote" output="false">
<cfset var returnarray = ArrayNew(1)>
<cfset var temp = "">
<cfquery name="empinfo" datasource="cfdocexamples">
SELECT firstname, lastname
FROM employee
</cfquery>
<cfloop query="empinfo" >
<cfobject component="name" name="tempname">
<cfset tempname.Firstname = #empinfo.firstname#>
<cfset tempname.Lastname = #empinfo.lastname#>
<cfset temp = ArrayAppend(returnarray, tempname)>
</cfloop>
<cfreturn returnarray>
</cffunction>
</cfcomponent>
When you invoke the web service, it returns an array of CFCs. Access the properties in the CFC by using dot notation,
as the following example shows:
<cfinvoke webservice ="http://localhost:8500/ws/cfcarray.cfc?wsdl"
method ="allNames"
returnVariable="thearray">
<cfif IsArray(thearray)>
<h1>loop through the employees</h1>
<p>thearray has <cfoutput>#ArrayLen(thearray)#</cfoutput> elements.</p>
<cfloop index="i" from="1" to="#ArrayLen(thearray)#">
<cfoutput>#thearray[i].firstname#, #thearray[i].lastname# </cfoutput><br>
</cfloop>
<cfelse>
<h1>Error: thearray is not an array</h1>
</cfif>
In this example, the style is document-literal. Examine the WSDL to determine the methods you can call and the
parameters for each method.
On the client side, the cfinvoke tag and other ColdFusion methods for calling web services handle the style
automatically. In most cases, no modifications are necessary. Similarly, when publishing CFCs as document-literal
style web services, ColdFusion automatically creates and manages the appropriate WSDL.
1111
To publish CFCs as document-literal style web services, specify cfcomponent style="document", along with the
other attributes required for document-literal style web services. For example, ColdFusion publishes the following
CFC using document-literal style:
<cfcomponent style="document" >
<cffunction
name = "getEmp"
returntype="string"
output = "no"
access = "remote">
<cfargument name="empid" required="yes" type="numeric">
<cfset var fullname = "">
<cfquery name="empinfo" datasource="cfdocexamples">
SELECT emp_id, firstname, lastname
FROM employee
WHERE emp_id = <cfqueryparam cfsqltype="cf_sql_integer"
value="#arguments.empid#">
</cfquery>
<cfif empinfo.recordcount gt 0>
<cfset fullname = empinfo.lastname & ", " & empinfo.firstname>
<cfelse>
<cfset fullname = "not found">
</cfif>
<cfreturn #fullname#>
</cffunction>
</cfcomponent>
1112
<cfinvoke
webservice = "http://some.cfc?wsdl"
returnVariable = "foo"
...
username="aName"
password="aPassword">
<cfoutput>#foo#</cfoutput>
ColdFusion inserts the user name/password string in the authorization request header as a base64 binary encoded
string, with a colon separating the user name and password. This method of passing the user name/password is
compatible with the HTTP basic authentication mechanism used by web servers.
The ColdFusion Administrator lets you predefine web services. As part of defining the web service, you can specify the
user name and password that ColdFusion includes as part of the request to the web service. Therefore, you do not have
to encode this information using the cfinvoke tag. For information on defining a web service in the ColdFusion
Administrator, see Configuring web services in the ColdFusion Administrator on page 1102.
Using ColdFusion to control access
Instead of letting the web server control access to your web services, you can handle the user name/password string in
your Application.cfc or Application.cfm file as part of your own security mechanism. In this case, you use the cflogin
tag to retrieve the user name/password information from the authorization header, decode the binary string, and
extract the user name and password, as the following excerpt from an Application.cfc onRequestStart method
shows:
<cflogin>
<cfset isAuthorized = false>
<cfif isDefined("cflogin")
<!--- Verify user name from cflogin.name and password from
cflogin.password using your authentication mechanism. --->
>
<cfset isAuthorized = true>
</cfif>
</cflogin>
<cfif not isAuthorized>
<!--- If the user does not pass a user name/password, return a 401 error.
The browser then prompts the user for a user name/password. --->
<cfheader statuscode="401">
<cfheader name="WWW-Authenticate" value="Basic realm=""Test""">
<cfabort>
</cfif>
This example does not show how to perform user verification. For more information on verification, see Securing
Applications on page 339.
publication. These types require consumers, especially ones that consume the web service using a technology other
than ColdFusion, to create special data structures to handle complex types.
2 Locally test the ColdFusion components implemented for web services before publishing them over the Internet.
1113
IsSOAPRequest, called to determine whether the CFC method is being called as a web service.
GetSOAPRequestHeader, called to retrieve a SOAP header set by the client.
GetSOAPRequest, called to retrieve a SOAP request sent by the client.
AddSOAPResponseHeader, called to set a SOAP header that is returned to the client.
Note: When used in a CFC, you can only use these functions in CFC methods if they are being used as web services. Use
the IsSOAPRequest function to determine whether the CFC method is being called as a web service.
The following example CFM page uses the AddSOAPRequestHeader, getSOAPRequest, and GetSOAPResponse
functions:
1114
<cfsavecontent variable="my_xml">
<Request xmlns="http://www.oasis-open.org/asap/0.9/asap.xsd">
<SenderKey>ss</SenderKey>
<ReceiverKey>zz</ReceiverKey>
<ResponseRequired>Yes</ResponseRequired>
<RequestID>id</RequestID>
</Request>
</cfsavecontent>
<cfset xml_obj = xmlparse(my_xml)>
<cfscript>
ws = CreateObject("webservice", "http://localhost:8500/soapexamples/HeaderFuncs.cfc?WSDL");
addSOAPRequestHeader(ws, "http://www.cfdevguide.com/", "testrequestheader", "#xml_obj#");
</cfscript>
<cfscript>
ret=ws.showSOAPHeaders();
inxml = getSOAPRequest(ws);
outxml = getSOAPResponse(ws);
</cfscript>
<cfoutput>
<h2>Return Value</h2>
<!--- This code is XML, so use HTMLCodeFormat. --->
The return value was #ret#
<h2>Complete Request XML</h2>
#htmlcodeformat(inxml)#
<h2>Complete Response XML</h2>
#htmlcodeformat(outxml)#
</cfoutput>
The following example CFC uses the IsSOAPRequest and AddSOAPResponseHeader functions:
1115
<cfcomponent>
<cffunction
name = "showSOAPHeaders"
returnType = "string"
output = "no"
access = "remote"
hint="After calling this function, use GetSOAPRequest and GetSOAPResponse to view
headers">
<cfset var xml_obj = "">
<cfset var ret = "">
<cfif IsSOAPRequest()>
<!--- Define a response header --->
<cfsavecontent variable="response_xml">
<ThisResponseHeader xmlns="http://www.cfdevguide.com">
<CreatedDateTime><cfoutput>#now()#</cfoutput></CreatedDateTime>
<ExpiresInterval>6000</ExpiresInterval>
</ThisResponseHeader>
</cfsavecontent>
<cfset xml_obj = xmlparse(response_xml)>
<!--- Add the response header --->
<cfscript>
addSOAPResponseHeader("http://www.cfdevguide.com/", "testresponseheader", "#xml_obj#");
ret = "Invoked as a web service. Use GetSOAPRequest and GetSOAPResponse to view headers.";
</cfscript>
<cfelse>
<cfset ret = "Not invoked as a web service">
</cfif>
<cfreturn ret>
</cffunction>
</cfcomponent>
Mapping the data types of a web service to consume to ColdFusion data types
Understanding how clients reference your ColdFusion data types when you publish a web service
numeric
SOAP-ENC:double
Boolean
SOAP-ENC:boolean
string
SOAP-ENC:string
array
SOAP-ENC:Array
numeric
SOAP-ENC:float
binary
xsd:base64Binary
1116
date
xsd:dateTime
complex type
This table shows that complex data types map to ColdFusion structures. ColdFusion structures offer a flexible way to
represent data. You can create structures that contain single-dimension arrays, multi-dimensional arrays, and other
structures.
The ColdFusion mapping of complex types to structures is not automatic. Accessing the data as a structure requires
some processing of the data. The next sections describe how to pass complex types to web services, and how to handle
complex types returned from web services.
Passing input parameters to web services as complex types
A web service can take a complex data type as input. In this situation, you can construct a ColdFusion structure that
models the complex data type, then pass the structure to the web service.
For example, the following excerpt from a WSDL file shows the definition of a complex type named Employee:
<s:complexType name="Employee">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1"
<s:element minOccurs="1" maxOccurs="1"
<s:element minOccurs="1" maxOccurs="1"
<s:element minOccurs="1" maxOccurs="1"
<s:element minOccurs="1" maxOccurs="1"
<s:element minOccurs="1" maxOccurs="1"
</s:sequence>
</s:complexType>
The Employee data type definition includes six elements, the data type of each element, and the name of each element.
Another excerpt from the WSDL file shows a message definition using the Employee data type. This message defines
an input parameter, as the following code shows:
<message name="updateEmployeeInfoSoapIn">
<part name="thestruct" type="s0:Employee" />
</message>
A third excerpt from the WSDL file shows the definition of an operation, named updateEmployeeInfo, possibly one
that updates the employee database with the employee information. This operation takes as input a parameter of type
Employee, as the following code shows:
<operation name="updateEmployeeInfo">
<input message="s0:updateEmployeeInfoSoapIn" />
</operation>
To call the updateEmployeeInfo operation, create a ColdFusion structure, initialize six fields of the structure that
correspond to the six elements of Employee, and then call the operation, as the following code shows:
1117
<!--- Create a structure using CFScript, then call the web service. --->
<cfscript>
stUser = structNew();
stUser.active = TRUE;
stUser.fname = "John";
stUser.lname = "Smith";
stUser.age = 23;
stUser.hiredate = createDate(2002,02,22);
stUser.number = 123.321;
ws = createObject("webservice", "http://somehost/EmployeeInfo.asmx?wsdl");
ws.updateEmployeeInfo(stUser);
</cfscript>
You can use structures for passing input parameters as complex types in many situations. However, to build a structure
to model a complex type, inspect the WSDL file for the web service to determine the layout of the complex type. This
process can take some practice.
Handling return values as complex types
When a web service returns a complex type, you can write that returned value directly to a ColdFusion variable.
The previous section used a complex data type named Employee to define an input parameter to an operation. A
WSDL file can also define a return value using the Employee type, as the following code shows:
<message name="updateEmployeeInfoSoapOut">
<part name="updateEmployeeInfoResult" type="s0:Employee" />
</message>
<operation name="updateEmployeeInfo">
<input message="s0:updateEmployeeInfoSoapIn" />
<output message="s0:updateEmployeeInfoSoapOut" />
</operation>
In this example, the operation updateEmployeeInfo takes a complex type as input and returns a complex type as
output. To handle the input parameter, you create a structure. To handle the returned value, you write it to a
ColdFusion variable, as the following example shows:
1118
<!--- Create a structure using CFScript, then call the web service. --->
<!--- Write the returned value to a ColdFusion variable. --->
<cfscript>
stUser = structNew();
stUser.active = TRUE;
stUser.fname = "John";
stUser.lname = "Smith";
stUser.age = 23;
stUser.hiredate = createDate(2002,02,22);
stUser.number = 123.321;
ws = createObject("webservice", "http://somehost/echosimple.asmx?wsdl");
myReturnVar = ws.echoStruct(stUser);
</cfscript>
<!--- Output the returned values. --->
<cfoutput>
<br>
<br>Name of employee is: #myReturnVar.fname##myReturnVar.lname#
<br>Active status: #myReturnVar.active#
<br>Age:#myReturnVar.age#
<br>Hire Date: #myReturnVar.hiredate#
<br>Favorite Number: #myReturnVar.number#
</cfoutput>
You access elements of the variable myReturnVar using dot notation in the same way that you access structure fields.
If a complex type has nested elements, in the way a structure can have multiple levels of nested fields, you use dot
notation to access the nested elements, as in a.b.c.d, to whatever nesting level is necessary.
However, the variable myReturnVar is not a ColdFusion structure. It is a container for the complex type, but has none
of the attributes of a ColdFusion structure. Calling the ColdFusion function isStruct on the variable returns False.
You can copy the contents of the variable to a ColdFusion structure, as the following example shows:
<cfscript>
...
ws = createObject("webservice", "http://somehost/echosimple.asmx?wsdl");
myReturnVar = ws.echoStruct(stUser);
realStruct = structNew();
realStruct.active = #myReturnVar.active#;
realStruct.fname = "#myReturnVar.fname#";
realStruct.lname = "#myReturnVar.lname#";
realStruct.age = #myReturnVar.age#;
realStruct.hiredate = #myReturnVar.hiredate#;
realStruct.number = #myReturnVar.number#;
</cfscript>
Calling IsStruct on realStruct returns True and you can use all ColdFusion structure functions to process it.
This example shows that ColdFusion variables and structures are useful for handling complex types returned from web
services. To understand how to access the elements of a complex type written to a ColdFusion variable, inspect the
WSDL file for the web service. The WSDL file defines the API to the web service and provides you with the information
necessary to handle data returned from it.
1119
This complex type defines a representation of a structure, where the structure keys and values can be any type.
In the WSDL mapping of a ColdFusion structure, each key-value pair in the structure points to the next element in the
structure except for the final field, which contains a value. Use dot notation to access the key-value pairs.
Publishing queries
ColdFusion publishes query data types as the WSDL type QueryBean. The QueryBean data type contains two
elements, as the following excerpt from a WSDL file shows:
<complexType name="QueryBean">
<all>
<element name="data" nillable="true" type="intf:ArrayOf_SOAP-ENC_Array" />
<element name="ColumnList" nillable="true"
type="intf:ArrayOf_SOAP-ENC_string" />
</all>
</complexType>
Description
ColumnList
data
1120
<complexType name="ArrayOf_SOAP-ENC_Array">
<complexContent>
<restriction base="SOAP-ENC:Array">
<attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="SOAP-ENC:Array[]" />
</restriction>
</complexContent>
</complexType>
<complexType name="ArrayOf_SOAP-ENC_string">
<complexContent>
<restriction base="SOAP-ENC:Array">
<attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="xsd:string[]" />
</restriction>
</complexContent>
</complexType>
Clients call this function after the web service request; web service CFCs call this function in
the web service CFC method.
GetSOAPResponse
GetSOAPRequest
Clients call this function after the web service request completes; web service CFCs cannot use
this method.
The following example uses the GetSOAPRequest and GetSOAPResponse functions in a web service client:
<cfscript>
ws = CreateObject("webservice", "http://localhost:8500/soapexamples/tester.cfc?WSDL");
addSOAPRequestHeader(ws, "http://mynamespace/", "username", "randy");
ret = ws.echo_me("value");
</cfscript>
<cfset soapreq = GetSOAPRequest(ws)>
<h2>SOAP Request</h2>
<cfdump var="#soapreq#">
<cfset soapresp = GetSOAPResponse(ws)>
<h2>SOAP Response</h2>
<cfdump var="#soapresp#">
...
The following example uses the GetSOAPRequest function in a web service CFC method:
1121
To run TCPMonitor:
1 On Windows and UNIX platforms, you can execute the TCPMonitor by launching the sniffer utility in the
2 Enter the values in the main window as described in the following table:
Field
Description
Listen Port#
Enter a local port number, such as 8123, to monitor for incoming connections. Instead of requesting
the usual port on which your server runs, you request this port. TCPMonitor intercepts the request
and forwards it to the Target Port.
Listener
Proxy
1122
Field
Description
Target Hostname
Target Port#
Enter the port number on the target machine to which TCPMonitor connects. For example, if you are
monitoring a service running on your local ColdFusion server in the server configuration, the default
port number is 8500.
Select this check box only to configure proxy support for TCPMonitor.
You can optionally specify the Listen Port#, Target Hostname and Target Port# values when invoking TCPMonitor
on the command line. The following is the syntax for TCPMonitor:
java org.apache.axis.utils.tcpmon [listening_port] [target_host] [target_port]
request in the Request panel before resending, and test the effects of different requests.
8 To change the ports, click Stop, change the port numbers, and click Start.
9 To add another listener, click the Admin tab and enter the values as described previously.
10 To end this TCPMonitor session, click Close.
cfchart
cfdocument
cfimage
cfmail
cfpop
1123
cfpdf
specify individual addresses, address ranges of the form 10-30, or * wild cards. You can specify IPv4 or IPv6
addresses.
For example, you can use the following address patterns:
10.*.*.*
10*.30-50.20-30
10:10:10:10:10:10:10-FF:*
2 On the Administrator Service > User Manager page, specify the users that can access the services. You must specify
the user name and password. Also specify the allowed services in the Exposed Services section of the page.
All the methods and attributes exposed through services can be found in WSDL. Attribute explanation is same as the
attributes of corresponding ColdFusion TAGS/Functions.
1124
The following example shows a section of a PHP page that adds a border to an image:
$input = new AddBorder();
//Fill in the class fields of $input to match your business logic
$input->serviceusername = "myuser";
$input->servicepassword = "mypassword";
$input->source = "http://myPHPSite/Images/image.jpg";
$input->thickness = "30";
$input->color = "blue";
$input->bordertype = "";
// call the operation
$response = $proxy->AddBorder($input);
1125
1126
ColdFusion Administrator.
For example, ColdFusion includes a Copytext sample applet that copies text from one text box to another. The
ColdFusion Setup automatically registers the applet in the Administrator. To use this applet, incorporate it on your
page. For example:
<cfform action = "copytext.cfm">
<cfapplet appletsource = "copytext" name = "copytext">
</cfform>
Interoperates with JSP pages: ColdFusion pages can include or forward to JSP pages, JSP pages can include or
forward to ColdFusion pages, and both types of pages can share data in persistent scopes.
Imports and uses JSP tag libraries: the cfimport tag imports JSP tag libraries and lets you use its tags.
ColdFusion pages are not JSP pages, however, and you cannot use most JSP syntax on ColdFusion pages. In particular,
you cannot use the following features on ColdFusion pages:
Include, Taglib, and Page directives: Instead, you use CFML import tag to import tag libraries, and the include (or
forward) method of the page context object returned by the ColdFusion GetPageContext function to include pages.
For more information, see Using JSP tags and tag libraries on page 1128 and Interoperating with JSP pages and
servlets on page 1129.
Expression, Declaration, and Scriptlet JSP scripting elements: Instead, you use CFML elements and expressions.
JSP comments: Instead, you use CFML comments. (ColdFusion ignores JSP comments and passes them to the
browser.)
1127
Standard JSP tags: Such as jsp:plugin, unless your J2EE server provides access to these tags in a JAR file. Instead, you
use ColdFusion tags and the PageContext object.
Standard Java classes and methods that make up the J2EE API
Custom-written Java objects, including the following:
Custom classes, including JavaBeans
Enterprise JavaBeans
ColdFusion pages use the cfobject tag to access Java objects.
ColdFusion searches for the objects in the following order:
1 The ColdFusion Java Dynamic Class Load directories:
2 Java archive (.jar) files in web_root/WEB-INF/lib
3 Class (.class) files in web_root/WEB-INF/classes
ColdFusion reloads classes from these directories, as described in the next section, About class loading.
1 The classpath specified on the JVM and Java Settings page in the ColdFusion Administrator.
2 The default JVM classpath.
1128
The PageContext object exposes several fields and methods that can be useful in J2EE integration. In particular, it
includes the include and forward methods that provide the equivalent of the corresponding standard JSP tags.
For more information on other features of the PageContext object, see Java documentation. You can find the Javadoc
description of this class at http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/PageContext.html.
If you share Request scope variables between a CFML page and a JSP page or servlet, all shared Request scope
variable names must be all-lowercase in the JSP page or servlet. Mixed case or all-uppercase variables cause null
pointer exceptions if CFML refers to these variables.
If you share Application or Session scope variables between a CFML page and a JSP page or servlet and use a named
ColdFusion application (the common usage), the variables on the JSP page or servlet are case-independent.
If you share the Application or Session scope variables between a CFML page and a JSP page or servlet, and use an
unnamed ColdFusion application, the variable names in the JSP page or servlet must be all lowercase.
When you specify a class name in the cfobject tag or CreateObject function, the name must be case-correct.
Guidelines
You can prevent problems by consistently using all-lowercase variable names.
In your CFML, use the same case as you do in your Java or JSP. Doing so does not change how the application
works, but does help prevent confusion.
1129
However, two standard JSP tags provide functionality that is useful in ColdFusion pages: the forward and include
tags invoke JSP pages and Java servlets. The PageContext object described in About GetPageContext and the
PageContext object section has forward and include methods that provide the same operations. For more
information about using these methods, see Accessing a JSP page or servlet from a ColdFusion page on page 1130.
Using custom JSP tags in a ColdFusion page
Follow these steps to use a custom JSP tag on a ColdFusion page:
Use a custom tag
1 Place the tag library, consisting of the taglibname.jar file, and the taglibname.tld file, if one is supplied, in the
web_root/WEB-INF/lib directory. The JSP custom tag library must be in this directory for you to use the cfimport
tag.
2 Restart ColdFusion.
3 In the ColdFusion page that uses a JSP tag from the tag library, specify the tag library name in a cfimport tag; for
example:
<cfimport taglib="/WEB-INF/lib/random.jar" prefix="random">
If the TLD file is not included in the JAR file, use the .tld extension in place of the .jar extension.
Note: The cfimport tag must be on the page that uses the imported tag. You cannot place the cfimport tag in
Application.cfm.
4 Use the custom tag using the form prefix:tagName; for example:
<random:number id="myNum" range="000000-999999" />
Note: You cannot use the cfsavecontent tag to suppress output of a custom JSP tag.
For more information on the Jakarta random tag library and how to use its tags, see the documentation at the Apache
Jakarta Taglibs project website, http://jakarta.apache.org/taglibs/index.html. The Taglibs project includes many open
source custom tag libraries.
1130
To pass parameters to the JSP page, include the parameters in the page URL.
For example, you could want to integrate an existing JSP customer response component into a new ColdFusion order
processing application. The order processing application provides the order number, total cost, and expected shipping
date, and the customer response component sends the response to the e-mail address on file for the particular
customer number. The ColdFusion application could use the following CFScript code to call the response JSP page:
urlParams =
"UID=#order.uid#&cost=#order.total#&orderNo=#order.orderNo#&shipDate=#order.shipDateNo#"
getPageContext().forward(URLEncodedFormat("/responsegen/responsegen.jsp?#urlParams#"));
To access a servlet that exposes the same functionality, you use the same code, although the URL would change. For
example, to run a servlet called HelloWorldServlet, you place the servlet .java or .class file in the serverroot/WEBINF/classes directory and access the servlet with the URL /servlet/HelloWorldServlet.
Accessing ColdFusion application and session variables in JSP pages
ColdFusion runs as a J2EE application on the J2EE application server. The J2EE application ServletContext is a data
structure that stores objects as attributes. A ColdFusion Application scope is represented as an attribute named by the
Application scope name. The attribute contains the scope values as a hash table. Therefore, you access ColdFusion
Application scope variable in a JSP page or servlet using the following format:
((Map)application.getAttribute("CFApplicationName"))).get("appVarName")
Similarly, the ColdFusion Session scope is a structure within the J2EE session. Because ColdFusion identifies sessions
by the application name. the session structure is contained in an attribute of the J2EE session that the application name
identifies. Therefore, you access ColdFusion session variables as follows:
((Map)(session.getAttribute("CFApplicationName"))).get("sessionVarName")
1131
Scope
Request
forward, include
Note: Shared Request scope variable names in the JSP page or servlet must be all-lowercase.
Session
Application
Note: When you share data between ColdFusion pages and JSP pages, be careful about data type conversion issues. For
more information, see Java and ColdFusion data type conversions on page 1139.
To share session variables, specify J2EE session management in the ColdFusion Administrator. For more information
on configuring and using J2EE Session scope management, see ColdFusion and J2EE session management on
page 312.
For example, you could put the customer order structure used in the previous example in the Session scope. Then, you
would not have to pass the order values as a set of parameters. Instead, the JSP pages could access the Session scope
variables directly, and the ColdFusion page would only require a line like the following to call the JSP page:
getPageContext().forward(URLEncodedFormat("/responsegen/responsegen.jsp"));
For examples of using the Request, Session, and Application scopes to share data between ColdFusion pages and JSP
pages, including samples of the appropriate JSP code, see Examples: using JSP with CFML on page 1132.
Note: When running in the server configuration, ColdFusion also shares the Form scope when calling a JSP or servlet. In
the J2EE configuration, however, sharing the Form scope is dependent on the J2EE application server. For example, JRun
shares the Form scope, IBM WebSphere does not. ColdFusion always shares the Request, Session, and Application scopes.
Unnamed ColdFusion Application and Session scopes
If you do not specify an application name in the This.name variable in the Application.cfc initialization code or by
using the ColdFusion cfapplication tag, the application is unnamed, and the Application scope corresponds to the
ColdFusion J2EE servlet context. ColdFusion, therefore, supports only a single unnamed application. If multiple
cfapplication tags and Application.cfc files do not specify an application name, all pages in these applications share
the servlet context as their Application scope.
All sessions of unnamed applications correspond directly to the session object of the J2EE application server. (If you do
not use J2EE session variables, ColdFusion ensures that the J2EE session lasts at least as long as the session time-out.)
You access an Application scope variable from a ColdFusion unnamed application in a JSP page using the following
format:
application.getAttribute("applicationVariableName")
Note: When you use application and session variables for the unnamed ColdFusion application in JSP pages and servlets,
the variable names must be case-correct. The characters in the variable name must have the same case as you used when
you created the variable in ColdFusion. You do not have to use case-correct application and session variable names for
named ColdFusion applications.
1132
Description
<cfapplication name="myApp"
sessionmanagement="yes">
Specifies the application name as myApp and enables session management. In most
applications, this tag is in the Application.cfm page.
<cfscript>
Request.myVariable = "This";
Session.myVariable = "is a";
Application.myVariable = "test.";
Sets ColdFusion Request, Session, and Application, scope variables. Uses the same
name, myVariable, for each variable.
GetPageContext().include("hello.jsp?name
=Bobby");
</cfscript>
Uses the GetPageContext function to get the current servlet page context for the
ColdFusion page. Uses the include method of the page context object to call the
hello.jsp page. Passes the name parameter in the URL.
The ColdFusion page calls the hello.jsp page. It displays the name parameter in a header and the three variables in the
remainder of the body.
<%@page import="java.util.*" %>
<h2>Hello <%= request.getParameter("name")%>!</h2>
<br>Request.myVariable: <%= request.getAttribute("myVariable")%>
<br>session.myVariable: <%= ((Map)(session.getAttribute("myApp"))).get("myVariable")%>
<br>Application.myVariable: <%=
((Map)(application.getAttribute("myApp"))).get("myVariable")%>
The following table describes the JSP code and its function (line breaks added for clarity):
1133
Code
Description
Imports the java.util package. This package contains methods required in the JSP page.
Displays the name passed as a URL parameter from the ColdFusion page. The parameter
name is case sensitive,
Note: The getParameter request method cannot get all ColdFusion page request
parameter values on some application servers. For example, on IBM WebSphere, you
cannot use getParameter to get form fields.
Uses the getAttribute method of the JSP request object to displays the value of the
Request scope variable myVariable.
The JSP page must use all lowercase characters to reference all request scope variables
that it shares with CFML pages. You can use any case on the CFML page, but if you use
mixed case or all uppercase on the JSP page, the variable is not set from the ColdFusion
page.
<br>session.myVariable: <%=
((Map)(session.getAttribute("myApp"))
).get("myVariable")%>
Uses the getAttribute method of the JSP session object to get the myApp object (the
Application scope). Casts this object to a Java Map object and uses the get method to
obtain the myVariable value for display.
CFML pages and JSP pages share Session variables independent of the variable name
case. The variable on the JSP page can have any case mixture and still receive the value
from the ColdFusion page. For example, instead of myVariable, you could use
MYVARIABLE or myvariable on this line.
<br>Application.myVariable:
<%=((Map)(application.getAttribute("m
yApp"))).get("myVariable")%>
Uses the getAttribute method of the JSP myApp application object to obtain the
value of myVariable in the Application scope.
CFML pages and JSP pages share Application variables independent of the variable
name case. The variable on the JSP page can have any case mixture and still receive the
value from the ColdFusion page. For example, instead of myVariable, you could use
MYVARIABLE or myvariable on this line.
1134
Code
Description
Imports the java.util package. This package contains methods required in the JSP
page.
<% request.setAttribute("myvariable",
"This");%>
Uses the setAttribute method of the JSP request object to set the value of the
Request scope variable myVariable.
The JSP page must use all lowercase characters to refer to all request scope
variables that it shares with CFML pages. You can use any case on the CFML page,
but if you use mixed case to all uppercase on the JSP page, the JSP page does not
share it with the ColdFusion page.
<%
((Map)session.getAttribute("myApp")).put(
"myVariable", "is a");%>
Uses the getAttribute method of the JSP session object to get the myApp
object (the Application scope). Casts this object to a Java Map object and uses the
set method to set the myVariable value.
CFML pages and JSP pages share Session variables independent of the variable
name case. The variable on the JSP page can have any case mixture and still share
the value with the ColdFusion page. For example, instead of myVariable, you could
use MYVARIABLE or myvariable on this line.
<%
((Map)application.getAttribute("myApp")).
put("myVariable","test.");%>
Uses the getAttribute method of the JSP application object to get myApp
object (the Application scope) and casts it to a Map object. It then sets the value of
myVariable in the myApp application scope object.
CFML pages and JSP pages share Application variables independent of the variable
name case. The variable on the JSP page can have any case mixture and still share
the value with the ColdFusion page. For example, instead of myVariable, you could
use MYVARIABLE or myvariable on this line.
<jsp:include page="hello.cfm">
<jsp:param name="name" value="Robert"/>
</jsp:include>
Sets the name parameter to Robert and calls the ColdFusion page hello.cfm.
The JSP page calls the following hello.cfm page. It displays the Name parameter in a heading and the three variables in
the remainder of the body.
<cfapplication name="myApp" sessionmanagement="yes">
<cfoutput>
<h2>Hello #URL.name#!</h2>
Request.myVariable: #Request.myVariable#<br>
Session.myVariable: #Session.myVariable#<br>
Application.myVariable: #Application.myVariable#<br>
</cfoutput>
The following table describes the CFML code and its function:
Code
Description
<cfapplication name="myApp"
sessionmanagement="yes">
<cfoutput><h2>Hello #URL.name#!</h2>
Displays the name passed using the jsp:param tag on the JSP page. The
parameter name is not case sensitive.
Request.myVariable:
#Request.myVariable#<br>
Session.myVariable:
#Session.myVariable#<br>
Application.myVariable:
#Application.myVariable#<br>
</cfoutput>
1135
Although the cfobject tag loads the class, it does not create an instance object. Only static methods and fields are
accessible immediately after the call to cfobject.
If you call a public non-static method on the object without first calling the init method, ColdFusion makes an
implicit call to the default constructor.
To call an object constructor explicitly, use the special ColdFusion init method with the appropriate arguments after
you use the cfobject tag; for example:
<cfobject type="Java" class="MyClass" name="myObj">
<cfset ret=myObj.init(arg1, arg2)>
Note: The init method is not a method of the object, but a ColdFusion identifier that calls the new function on the class
constructor. So, if a Java object has an init method, a name conflict exists and you cannot call the object init method.
To have persistent access to an object, use the init function, because it returns a reference to an instance of the object,
and cfobject does not.
An object created using cfobject or returned by other objects is implicitly released at the end of the ColdFusion page
execution.
Using properties
Use the following coding syntax to access properties if the object does either of the following actions:
1136
obj.property = "somevalue">
value = obj.property>
Note: ColdFusion does not require consistently capitalized property and method names. However, it is good
programming practice to use the same case in ColdFusion as you do in Java to ensure consistency.
Calling methods
Object methods usually take zero or more arguments. Some methods return values, while others might not. Use the
following techniques to call methods:
1 If the method has no arguments, follow the method name with empty parentheses, as in the following cfset tag:
<cfset retVal = obj.Method1()>
2 If the method has one or more arguments, place the arguments in parentheses, separated by commas, as in the
following example, which has one integer argument and one string argument:
<cfset x = 23>
<cfset retVal = obj.Method1(x, "a string literal")>
Note: When you invoke a Java method, the type of the data being used is important. For more information see Java and
ColdFusion data type conversions on page 1139.
Calling JavaBean get and set methods
ColdFusion can automatically invoke getPropertyName() and setPropertyName(value) methods if a Java class
conforms to the JavaBeans pattern. As a result, you can set or get the property by referencing it directly, without having
to explicitly invoke a method.
For example, if the myFishTank class is a JavaBean, the following code returns the results of calling the getTotalFish()
method on the myFish object:
<cfoutput>
There are currently #myFish.TotalFish# fish in the tank.
</cfoutput>
The following example adds one guppy to a myFish object by implicitly calling the setGuppyCount(int number)
method:
<cfset myFish.GuppyCount = myFish.GuppyCount + 1>
Note: You can use the direct reference method to get or set values in some classes that have getProperty and setProperty
methods but do not conform fully to the JavaBean pattern. However, you cannot use this technique for all classes that
have getProperty and setProperty methods. For example, you cannot directly reference any of the following standard Java
classes, or classes derived from them: Date, Boolean, Short, Integer, Long, Float, Double, Char, Byte, String, List, Array.
Calling nested objects
ColdFusion supports nested (scoped) object calls. For example, if an object method returns another object and you
invoke a property or method on that object, you can use the following syntax:
<cfset prop = myObj.X.Property>.
Similarly, you can use code such as the following CFScript line:
GetPageContext().include("hello.jsp?name=Bobby");
In this code, the ColdFusion GetPageContext function returns a Java PageContext object, and the line invokes the
include method of the PageContext object.
1137
1138
JobGrade = grade;
}
public void SetJobGrade(String Grade) {
if (Grade.equals("CEO")) {
JobGrade = 3;
}
else if (Grade.equals("MANAGER")) {
JobGrade = 2;
}
else if (Grade.equals("DEVELOPER")) {
JobGrade = 1;
}
}
public int GetJobGrade() {
return JobGrade;
}
}
When you view the page in your browser, you get the following output:
Employee name is john doe
Reviewing the code
The following table describes the CFML code and its function:
Code
Description
Loads the Employee Java class and gives it an object name of emp.
Does not call a constructor. ColdFusion calls the default constructor when it first uses
the class; in this case, when it processes the next line.
1139
Code
Description
<cfset emp.firstname="john">
<cfset emp.lastname="doe">
<cfset firstname=emp.firstname>
<cfset lastname=emp.lastname>
<cfoutput>
Employee name is #firstname# #lastname#
</cfoutput>
Java considerations
The following points are important when you write a ColdFusion page that uses a Java class object:
The Java class name is case sensitive. Ensure that the Java code and the CFML code use Employee as the class name.
Although Java method and field names are case sensitive, ColdFusion variables are not case sensitive, and
ColdFusion does any necessary case conversions. As a result, the sample code works even though the CFML uses
emp.firstname and emp.lastname; the Java source code uses FirstName and LastName for these fields.
If you do not call the constructor (or, as in this example, comment it out), ColdFusion automatically runs the
default constructor when it first uses the class.
Using an alternate constructor
The following ColdFusion page explicitly calls one of the alternate constructors for the Employee object:
<html>
<body>
<cfobject action="create" type="java" class="Employee" name="emp">
<cfset emp.init("John", "Doe", 100000.00, 10)>
<cfset firstname=emp.firstname>
<cfset lastname=emp.lastname>
<cfset salary=emp.GetSalary()>
<cfset grade=emp.GetJobGrade()>
<cfoutput>
Employee name is #firstname# #lastname#<br>
Employee salary #DollarFormat(Salary)#<br>
Employee Job Grade #grade#
</cfoutput>
</body>
</html>
In this example, the constructor takes four arguments: the first two are strings, the third is a float, and the fourth is an
integer.
1140
Under most situations, when the method names are not ambiguous, ColdFusion can determine the data types that a
Java object requires, and often it can convert ColdFusion data to the required types. For example, ColdFusion text
strings are implicitly converted to the Java String type. Similarly, if a Java object contains a doIt method that expects a
parameter of type int, and CFML is issuing a doIt call with a CFML variable x that contains an integer value,
ColdFusion converts the variable x to Java int type. However, ambiguous situations can result from Java method
overloading, where a class has multiple implementations of the same method that differ only in their parameter types.
Default data type conversion
Whenever possible, ColdFusion automatically matches Java types to ColdFusion types.
The following table lists how ColdFusion converts ColdFusion data values to Java data types when passing arguments.
The left column represents the underlying ColdFusion representation of its data. The right column indicates the Java
data types into which ColdFusion can automatically convert the data:
CFML
Java
Integer
short, int, long (short and int can result in a loss of precision).
Real number
Boolean
boolean
Date-time
java.util.Date
String
short, int, long, float, double, java.util.Date, when a CFML string represents a number or date.
boolean, for strings with the value Yes, No, True, and False (case-insensitive).
Array
Structure
java.util.Map
Query object
java.util.Map
Not supported.
ColdFusion component
Not applicable.
The following table lists how ColdFusion converts data returned by Java methods to ColdFusion data types:
Java
CFML
boolean/Boolean
Boolean
byte/Byte
String
char/Char
String
short/Short
Integer
int/Integer
Integer
long/Long
Integer
float/Float
Real Number
1141
Java
CFML
double/Double
Real Number
String
String
java.util.Date
Date-time
java.util.List
Comma-delimited list
byte[]
Array
char[]
Array
boolean[]
Array
String[]
Array
java.util.Vector
Array
java.util.Map
Structure
The 1 could be interpreted as a string or as a number, so no way exists to know which method implementation to
use. When ColdFusion encounters such an ambiguity, it throws a user exception.
The ColdFusion JavaCast function helps you resolve such issues by specifying the Java type of a variable, as in the
following line:
<cfset emp.SetJobGrade(JavaCast("int", "1"))>
The JavaCast function takes two parameters: a string representing the Java data type, and the variable whose type you
are setting. You can specify the following Java data types: boolean, int, long, float, double, and String.
For more information about the JavaCast function, see the CFML Reference.
1142
The myException class has the following code. It throws an exception with a message that is passed to it, or if no
argument is passed, it throws a canned exception.
//class myException
public class myException extends Exception
{
public myException(String msg) {
super(msg);
}
public myException() {
super("Error Message from myException");
}
}
The testException class contains one method, doException, which throws a myException error with an error message,
as follows:
public class testException {
public testException ()
{
}
public void doException() throws myException {
throw new myException("Throwing an exception from testException class");
}
}
1143
<cfscript>
function GetHostAddress(host) {
// Define the function local variables.
var iaddrClass="";
var address="";
// Initialize the Java class.
iaddrClass=CreateObject("java", "java.net.InetAddress");
// Get the address object.
address=iaddrClass.getByName(host);
// Return the address
return address.getHostAddress();
}
</cfscript>
<cfoutput>#gethostaddress("adobe.com")#</cfoutput>
Using an EJB
ColdFusion can use EJBs that JRun 4.0 servers provide. The JRun server jrun.jar file must have the same version as the
jrun.jar file in ColdFusion.
To call an EJB, you use cfobject to create and call the appropriate objects. Before you use an EJB, do the following:
1 Have a properly deployed EJB running on a J2EE server. The bean must be registered with the JNDI server.
2 Have the following information:
from this class to define the information that you use to locate the EJB. Because you only use fields, you do not
initialize the object.
2 Use the cfobject tag to create a java.util.Properties class object to contain the context object properties.
3 Call the init method to initialize the Properties object.
4 Set the Properties object to contain the properties that are required to create an initial JNDI naming context. These
properties include the INITIAL_CONTEXT_FACTORY and PROVIDER_URL properties. You could also need to
provide SECURITY_PRINCIPAL and SECURITY_CREDENTIALS values required for secure access to the
naming context. For more information on these properties, see the JNDI documentation.
5 Use the cfobject tag to create the JNDI InitialContext (javax.naming. InitialContext) object.
6 Call the init method for the InitialContext object with the Properties object values to initialize the object.
7 Call the lookup method of the InitialContextext object to get a reference to the home interface for the bean that
you want. Specify the JNDI name of the bean as the lookup argument.
8 Call the create method of the bean home object to create an instance of the bean. If you are using Entity beans,
you typically use a finder method instead. A finder method locates one or more existing entity beans.
1144
9 Now you can use the bean methods as required by your application.
10 When finished, call the close method of the context object to close the object.
The following code shows this process using a simple Java Entity bean on a JRun 4.0 server. It calls the getMessage
method of the bean to obtain a message.
<html>
<head>
<title>cfobject Test</title>
</head>
<body>
<H1>cfobject Test</H1>
<!--- Create the Context object to get at the static fields. --->
<CFOBJECT
action=create
name=ctx
type="JAVA"
class="javax.naming.Context">
<!--- Create the Properties object and call an explicit constructor--->
<CFOBJECT
action=create
name=prop
type="JAVA"
class="java.util.Properties">
<!--- Call the init method (provided by cfobject)
to invoke the Properties object constructor. --->
<cfset prop.init()>
<!--- Specify the properties These are required for a remote server only --->
<cfset prop.put(ctx.INITIAL_CONTEXT_FACTORY, "jrun.naming.JRunContextFactory")>
<cfset prop.put(ctx.PROVIDER_URL, "localhost:2908")>
<!--- <cfset prop.put(ctx.SECURITY_PRINCIPAL, "admin")>
<cfset prop.put(ctx.SECURITY_CREDENTIALS, "admin")>
--->
<!--- Create the InitialContext --->
<CFOBJECT
action=create
name=initContext
type="JAVA"
class="javax.naming.InitialContext">
<!--- Call the init method (provided through cfobject)
to pass the properties to the InitialContext constructor. --->
<cfset initContext.init(prop)>
1145
Description
ReverseString
ReverseStringArray
Add
Overloaded: Adds and returns two integers or floats or adds the mPublicInt members of two
Example class objects and returns an Example class object.
SumArray
SumObjArray
Adds the values of the mPublicInt members of an array of Example class objects and returns an
Example class object.
ReverseArray
Flip
1146
1147
1148
<!--- Use the Java object to flip a Boolean value, reverse a string,
add two integers, and add two float numbers --->
<cfset c=obj.Flip(true)>
<cfset StringVal=obj.ReverseString("This is a test")>
<cfset IntVal=obj.Add(JavaCast("int",20),JavaCast("int",30))>
<cfset FloatVal=obj.Add(JavaCast("float",2.56),JavaCast("float",3.51))>
<!--- Display the results --->
<cfoutput>
<br>
StringVal: #StringVal#<br>
IntVal: #IntVal#<br>
FloatVal: #FloatVal#<br>
<br>
</cfoutput>
<!--- Create a two-element array, sum its values,
and reverse its elements --->
<cfset intarray=ArrayNew(1)>
<cfset intarray[1]=1>
<cfset intarray[2]=2>
<cfset IntVal=obj.sumarray(intarray)>
<cfset reversedarray=obj.ReverseArray(intarray)>
<!--- Display the results --->
<cfoutput>
<br>
IntVal1 :#IntVal#<br>
array1: #reversedarray[1]#<br>
array2: #reversedarray[2]#<br>
<br>
</cfoutput><br>
<!--- Create a ColdFusion array containing two Example objects.
Use the SumObjArray method to add the objects in the array
Get the public member of the resulting object--->
<cfset oa=ArrayNew(1)>
<cfobject action=create type=java class=Example name=obj1>
<cfset VOID=obj1.init(JavaCast("int",5))>
<cfobject action=create type=java class=Example name=obj2>
<cfset VOID=obj2.init(JavaCast("int",10))>
<cfset oa[1] = obj1>
<cfset oa[2] = obj2>
<cfset result = obj.SumObjArray(oa)>
<cfset intval = result.mPublicInt>
<!--- Display the results --->
<cfoutput>
<br>
intval1: #intval#<br>
<br>
</cfoutput><br>
</body>
</html>
1149
Directly access and control Microsoft products, such as Word, Excel, or PowerPoint.
Use existing .NET components.
Use .NET assemblies that you create to leverage features that are difficult to use or not available in ColdFusion or
Java. (Because ColdFusion is a J2EE application, if you cannot code a feature in CFML, it is more efficient to create
it in Java than to use .NET.)
The .NET classes that your application uses do not have to be local; your ColdFusion application can access .NET
components that are located on remote systems, even systems that are located outside your firewall. Also, the
ColdFusion system does not require .NET run-time software installed to use remote .NET components, so ColdFusion
running on a UNIX, Linux, Solaris, or OS-X system can access and use .NET assemblies.
You can use the cfobject tag or CreateObject function to create a reference to a .NET class object, by specifying
either .NET or dotnet as the object type. You use the reference to access the .NET class fields and call the .NET class
methods. This technique provides a tightly coupled, stateful, efficient method for accessing .NET classes from
ColdFusion. As an alternative, your .NET application can make the class methods available as web services; however,
using a web service is less reliable, has lower performance, and is less scalable than using ColdFusion objects for the
.NET classes.
Note: .NET applications cannot access ColdFusion component functions directly. You can make the functions available
as web services by specifying remote access. For more information on creating ColdFusion web services, see Using Web
Services on page 1093.
Because you use the .NET assembly classes the same way that you use any other ColdFusion object, you do not have
to understand the details of .NET technology; you only have to understand how to use the specific .NET class that you
are accessing. Code that uses a .NET method can be as simple as the following lines:
<cfobject type = ".NET" name = "mathInstance" class = "mathClass"
assembly = "C:/Net/Assemblies/math.dll">
<cfset myVar = mathInstance.multiply(1,2)>
If you make a change in the .NET assembly, ColdFusion automatically recognizes the change and uses that version
for the next invocation.
1150
CFML Page
Application view
.NET Assembly
Invokes
Invokes
JNBShare.dll
Java Proxy
JNBDotNetSide.
exe.config
Uses
Uses
Specifies
assembly classes
JNBCore.jar
(installed on all
TCP/Binary or
ColdFuson
systems)
HTTP/SOAP
communications
ColdFusion Side
JNBDotNetSide.exe
(runs as a Windows
service)
.NET Side
If your .NET assemblies are on the local system, ColdFusion automatically creates and manages all required proxies
and configuration information. Ensure only that the .NET extension is installed on your system and that the
ColdFusion .NET Service is running. You can use the cfobject tag or CreateObject function to access the
assemblies without any additional steps.
1151
If the assemblies are on a remote system, you install and use the ColdFusion .NET extension software on the .NET
system to create Java proxies for the .NET classes, and then move or copy them to the ColdFusion system. Also edit
the JNBDotNetSide.exe.config file on the remote system to specify the .NET classes you use. The .NET system requires
the following .NET extension software:
JNBDotNetSide.exe, the .NET-side agent that communicates with the ColdFusion system (normally run as the
ColdFusion .NET service).
JNBDotNetSide.exe.config, a configuration file that identifies the .NET assemblies that ColdFusion can access.
jnbproxy.exe and jnbproxyGui.exe are command line and GUI-based programs that generate the Java proxies that
represent the .NET assemblies.
Additional support files, including JNBShare.dll, which invoke the .NET assembly classes.
For information on installing the ColdFusion .NET extension, see Installing ColdFusion guide.
Note: When you install a new .NET version, reinstall the ColdFusion .NET extension.
A local access method for .NET objects that are installed on the ColdFusion system
A remote access method for .NET objects located on other systems.
For both methods, install the ColdFusion .NET extension and run the ColdFusion .NET service on the system that
hosts the assemblies. You need not install the extension or run the service on a ColdFusion system that accesses only
remote assemblies. For information on installing the ColdFusion .NET extension, see Installing ColdFusion guide.
1152
2 If the .NET assemblies reside only on the remote system, generate proxy JAR files on that system that represent the
assemblies (see Generating the Java proxy classes on page 1152). Then copy or move the proxy files to the local
system. If identical .NET assemblies also reside on the local system, you can skip this step.
3 Configure the .NET-side system for remote access (see Configuring the .NET-side system on page 1154).
The jnbridge directory includes a jnbproxy.chm Windows Help file with more complete documentation on the
JNBridge technology that powers the ColdFusion .NET feature, including detailed information on both the
jnbproxyGui and jnbproxy programs.
The jnbridge\docs subdirectory includes additional documentation, including users guide.pdf, a PDF version of the
information in the Help file.
Note: The JNBridge documentation includes information on features that are not supported in ColdFusion. ColdFusion,
for example, does not support access from .NET assemblies to ColdFusion or memory-only communication.
Using the jnbproxyGui tool
You use the jnbproxyGui program to generate a proxy JAR file.
Generate and install a proxy JAR
1 Start JNBProxyGui.exe.
2 The first time you run the program, it displays the Enter Java Options dialog box. Configure the options, and click OK.
You can change the configuration settings at a later time by selecting Project > Java Options.
On a system with ColdFusion: If ColdFusion is currently running on this system, ensure that the Start Java
Automatically option, located on the right side of the JNBProxy Enter Java Options (Project > Java Options) dialog
box is cleared. Leave the default values for the other settings.
When you open an existing project, you could get a Restart Java Side pop-up window with the message "You must
stop and restart the Java side before these changes to the classpath can take effect." You can ignore this message and
click OK to proceed.
When you start the program, the Java Options dialog box could appear. You do not have to change anything; click
OK or Cancel to open the Launch JNBProxy dialog box.
1153
In some cases, JNBProxyGui could behave as follows when the Start Java Automatically option is not selected.
On a system without ColdFusion: If ColdFusion is not currently running on the system, ensure that the following
options, which are located on the right side of the interface, are set. Leave the default values for the other settings.
Specify the bcel.jar file. The ColdFusion server installer places this file in the cfroot\lib directory. The J2EE
installer places the file in the cf_webapp_root\WEB-INF\cfusion\lib directory.
3 In the Launch JNBProxy dialog box, select Create New Java > .NET Project, and click OK.
4 In the main Java proxy generation interface, set up and build a project:
a If you have not already done so, add the directory that contains your assembly files to the JNBProxy your project.
Select Project >Edit Assembly List. In the Assembly List dialog box, click the Add button. In the New Assembly
List Element dialog box, navigate to the directory that contains your assemblies. Select the directory (or
directories) in the tree, and click OK. Then click OK in the Edit Assembly List dialog box.
b Open the Locate Assembly File dialog box (Project > Add Classes From Assembly File) and navigate to the
directory that you added to the assembly list in step a. Select the assembly file or files that contain classes that
require proxies and click OK.
c The classes in the selected file, and other .NET core classes on which they depend, appear in the Environment
pane. Select all classes for which you want proxies in your JAR file, and click the Add+ button to add the selected
classes and all supporting classes.
d In the Exposed Proxies list, select the classes to include in the JAR file. Normally, select all the listed classes,
JAR file in which to save the generated proxies, and click Save.
f
After the project is built, select File > Save Project and specify the file in which to save your project.
The next time you run the jnbproxyGui program, you can select your project and reuse your previous settings,
including the Assembly List.
5 Copy the JAR file to a directory on your ColdFusion system. You specify this path in the cfobject tag assembly
attribute.
Supporting classes
JNBProxy can generate proxies not only for the .NET classes that are explicitly listed, but also for supporting classes. A
supporting class for a given .NET class is any class that could be needed as a direct or indirect result of using that .NET
class. For a given .NET class, supporting classes include all of the following:
The class.
The classs superclass or superinterface (if it exists) and all of its supporting classes.
The classs implemented interfaces (if any) and all of their supporting classes.
For each field in the class:
The fields class and all of its supporting classes.
For each of the fields index parameters, the parameters class and all of its supporting classes.
1154
For local assemblies, edit this file only if you do not use the default port, or if you use SSL security.
For a .NET assembly on a remote machine, register the assemblies in this file to make it accessible to ColdFusion.
Edit the configuration file
1 Ensure that the following lines are in the <configSections> subsection of the <configuration> section:
<jnbridge>
<javaToDotNetConfig scheme="Protocol" port="local port number"
useSSL="true|false" certificateLocation="server certificate path"/>
</jnbridge>
The scheme attribute specifies the communications protocol, and must be jtcp or http.
The port number is the port of the .NET-side agent, normally 6086.
The useSSL attribute specifies whether to use SSL for secure communications. The attribute is optional; the
default is to not use SSL.
The certificateLocation attribute specifies the location of the server SSL certificate. It is required only if the
useSSL attribute is true.
These settings must be the same as the corresponding attributes in your cfobject tag.
2 If the .NET assemblies are on a remote system, specify the assemblies that ColdFusion accesses by adding the
1155
<assemblyList>
<assembly file="path to assembly or fully qualified name"/>
...
</assemblyList>
3 Stop and restart the .NET-side agent, if it is running. For example, on a ColdFusion system, restart the ColdFusion
.NET Service. Your ColdFusion application can now access the .NET classes that you configured.
The following example is a bare-bones JNBDotNetSide.exe.config file that specifies a .NET-side TCP server
configuration. The server communicates by using TCP binary mode and listens on port 6086. Java clients can access \\x
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<sectionGroup name="jnbridge">
<section name="dotNetToJavaConfig"
type="System.Configuration.SingleTagSectionHandler"/>
<section name="javaToDotNetConfig"
type="System.Configuration.SingleTagSectionHandler"/>
<section name="tcpNoDelay"
type="System.Configuration.SingleTagSectionHandler"/>
<section name="javaSideDeclarations"
type="System.Configuration.NameValueSectionHandler"/>
<section name="assemblyList"
type="com.jnbridge.jnbcore.AssemblyListHandler, JNBShare"/>
</sectionGroup>
<jnbridge>
<javaToDotNetConfig scheme="jtcp" port="6086"/>
<assemblyList>
\\x
<assembly file="System.Windows.Forms, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</assemblyList>
</jnbridge>
</configuration>
Using CFScript and the CreateObject function, you can do the following:
<cfscript>
mathInstance = CreateObject(".NET", "mathClass",
"C:/Net/Assemblies/math.dll");
myVar = mathInstance.multiply(1,2);
</cfscript>
Note: You cannot load two DLLs with same fully qualified name. ColdFusion always uses the first DLL that it accesses
until the server is restarted. For example, if page1.cfm uses c:\dev\a.dll and page2.cfm uses c:\dev2\a.dll, and both DLLs
have the same fully qualified name, the first DLL file to be loaded remains loaded, and both CFML pages use it.
1156
When you create objects and access class methods and fields, and convert data types between ColdFusion and .NET,
be aware of the following considerations and limitations:
Data type conversion considerations described in Converting between .NET and ColdFusion data types on
page 1157
Limitations described in the Limitations section of cfobject: .NET object in the CFML Reference.
If the class has a default constructor, ColdFusion automatically calls the constructor when you first invoke a nonstatic method of the object.
If the class does not have a default constructor, or if the class has multiple constructors and you do not want to use
the default, call the special init method of the ColdFusion object. The cfobject tag automatically creates init
methods for all class constructors. Using the init method causes ColdFusion to call the class constructor with the
corresponding number and types of parameters. For example, the following tags cause ColdFusion to call the
MyClass constructor that takes two integer parameters:
<cfobject type=".NET" name="myObj" class="com.myCo.MyClass"
assembly="c:\assemblies\myLib.dll">
<cfset myObj.init(10, 5)>
Note: ColdFusion does not create instances of objects if you use only their static methods.
Calling methods
You call .NET methods in the same way that you use any other ColdFusion object methods. For example, if the
MyClass class has a getName method that takes a numeric ID and returns a name, you would call the method as
follows:
<cfset theID="2343">
<cfset userName=mObj.getName(theID)>
For example, if the .NET class has a public field named accountID, you can access and change its value by using the
Get_accountID() and Set_accountID() methods, as follows:
<cfobject type=".NET" class="com.myCo.MyClass"
assembly="c:\assemblies\myLib.dll" name="myObj">
<cfset theAccount=myObj.Get_accountID()>
<cfset myObj.Set_accountID(theAccount + 1)>
You can access, but not modify final fields, so you can only call Get_fieldName() for these fields.
1157
Java type
ColdFusion type
sbyte
byte
Integer
byte
short
Integer
short
short
Integer
ushort
int
Integer
int
int
Integer
uint
long
Number
char
char
Integer or string
long
long
Number
ulong
float
Number
float
float
Number
double
double
Number
The returned number retains greater precision than is normally displayed in ColdFusion.
Use the PrecisionEvaluate function to access and display the full precision of a returned
double value. You can also pass a value with full double precision to a .NET method.
bool
boolean
enum
Boolean
Not converted, but enumerator elements can be accessed directly by using the format
Enumerator_variable.enumerator, as in MyColor.Red
array
array
Array
string
String
String
System.Collections.ArrayLis java.util.ArrayList
t
Array
System.Collections.Hashtab java.util.Hashtable
le
Structure
Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert
ColdFusion Arrays to .NET ArrayLists.
Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert
ColdFusion Structures to .NET Hashtables
1158
.NET type
Java type
System.Data.DataTable
ColdFusion type
Query
Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert
ColdFusion Queries to .NET DataTables
System.DateTime
java.util.Date
decimal
System.Decimal
System.Object
Date/time
ColdFusion automatically converts returned decimal and System.Decimal values to ColdFusion string
representations.
Ensuring decimal and date/time conversions
ColdFusion converts .NET decimal or System.Decimal types only if the proxy for System.Decimal is a value type proxy.
Similarly, it converts .NET System.DateTime values to ColdFusion Date-time values only if the proxy for
System.DateTime is a value type proxy. The ColdFusion server always uses value proxies when it generates these
proxies. If you use the JNBProxyGUI.exe tool to generate the proxy, however, make sure to generate the proxy for
System.Decimal as value type.
Converting data to System.Object type
When a .NET method specifies System.Object (as opposed to a specific Object subclass, such as System.Boolean)
as the argument type, and you want to pass primitive values as arguments to that method, use the javacast function
to identify the data conversion. Once ColdFusion knows the data type, it automatically converts to the appropriate
.NET type. Here is the table that describes the conversion rule from ColdFusion type to .NET type.
.NET Type
bool / System.Boolean
boolean
bool[] / System.Boolean[]
boolean[]
char / System.Char
char
char[] / System.Char[]
char[]
double / System.Double
double
double[] / System.Double[]
double[]
float / System.Single
float
float[] / System.Single[]
float[]
1159
int / System.Int32
int
int[] / System.Int32[]
int[]
long / System.Int64
long
long[] / System.Int64[]
long[]
sbyte / System.Sbyte
byte
byte []
short / System.Int16
short
short[] / System.Int16[]
short[]
System.Decimal
bigdecimal
System.String
String
Note: You do not have to use a JavaCast function to convert ColdFusion string variables. They are automatically
converted to .NET System.String.
Create special objects for .NET primitive unsigned data types, such as byte (unsigned byte), ushort (unsigned short),
uint (unsigned int) and ulong (unsigned long), for which no corresponding java types exist. The following table lists
the .NET primitive types and the corresponding class you must use.
.NET type
byte / System.Byte
System.BoxedByte
ushort / System.UInt16
System.BoxedUShort
uint / System.UInt32
System.BoxedUInt
ulong / System.UInt64
System.BoxedULong
Use the createObject function or cfobject tag to create these special objects, in the same manner as you create
other .NET classes, before you use them in your assignment statement. For example, the following line creates a ushort
representation of the value 100:
<cfset boxedUShort = createObject(".NET". "System.BoxedUShort").init(100)>
The following example creates a System.Hashtable object and populates it with examples of all types of primitives.
1160
Similarly, if a .NET class has methods myFunc(int) and myFunc(String), use the JavaCast method to convert your
ColdFusion variable to the Java int or String data type, as shown in the following line:
myFunc(JavaCast(String, "123");
In some cases, the JavaCast function cannot eliminate ambiguity because a single Java type corresponds to multiple
.NET types. In these cases, ColdFusion creates a proxy with only one method, which uses the .NET data type that
corresponds directly to a Java type.
For example, if the .NET class has methods myFunc(ulong) and myFunc(float), the generated proxy has only one
method. This method calls myFunc(float), because the Java float type used to handle ColdFusion floating-point
numbers corresponds directly to the .NET float type. In this case, you can never call the .NET myFunc(ulong) method.
1161
Use associative array notation to properly access .NET Hashtable data from ColdFusion
You cannot use ColdFusion variables directly in parameters that take Hashtable, ArrayList, or DataTable input.
You can disable automatic conversion of complex .NET data to ColdFusion types.
You can manually convert complex .NET data to ColdFusion types.
Using Hashtable data in ColdFusion
.NET Hashtables are case sensitive, but most methods of ColdFusion structure access are not case sensitive. Only
associative array notation of the form structName["keyName"] is case sensitive. When .NET Hashtables are
converted to CF structure, the entire data set is converted, even if the element keys differ only in case. Therefore, to get
the values of the keys that differ only in case, use associative array notation.
The following example shows this issue. It creates a Hashtable object with three entries whose key values vary only in
case. In the example, output using dot-delimited structure notation always returns the same value, corresponding to
the all-uppercase key, but associative array notation returns the correct result.
<!--- Create a Hashtable and convert it to a ColdFusion structure. --->
<cfset table = createObject(".NET", "System.Collections.Hashtable")>
<cfset table.add("Key", "Value1")>
<cfset table.add("KEY", "Value2")>
<cfset table.add("key", "Value3")>
<cfset cftable = DotNetToCFType(table)>
<cfdump var="#cftable#">
<h3>Using dot notation</h3>
Key : <cfoutput>#cftable.Key#</cfoutput><br>
KEY : <cfoutput>#cftable.KEY#</cfoutput><br>
key : <cfoutput>#cftable.key#</cfoutput><br>
<p>
<h3>Using associative array notation</h3>
Key : <cfoutput>#cftable["Key"]#</cfoutput><br>
KEY : <cfoutput>#cftable["KEY"]#</cfoutput><br>
key : <cfoutput>#cftable["key"]#</cfoutput><br>
1162
ColdFusion Code:
<cfset cflist = netObject.getList()>
<cfloop array="#cflist#" index="item">
<cfoutput>#item#</cfoutput><br>
</cfloop>
<cfif cflist[3]>
<cfoutput>Third element in the list is true</cfoutput>
</cfif>
ColdFusion code:
<cfset query1 = netObject.datasetMethod()>
<cfoutput query="query1">
Query1.CurrentRow = #query1.CurrentRow#<br>
</cfoutput>
1163
If a collection or DataTable returned by a .NET method is large and you only want a small subset of the data. If auto
conversion is enabled, ColdFusion creates a data structure with all the objects fields. Creating the structure could
take significant time and resources, because ColdFusion must invoke .NET methods internally to get each of the
fields. You can disable the automatic conversion and retrieve the fields or data from .NET objects like any other
objects.
If you invoke a .NET method that returns a complex variable, and then pass the variable to another .NET method
as argument. If automatic conversion is enabled, you cannot pass the Hashtable object from the first method
directly to the second method.
To disable automatic conversion, set the JVM coldfusion.dotnet.disableautoconversion system property to true. For
example, in a ColdFusion stand-alone server, or if you use JRun as your J2EE server, include the following setting in
the JVM.config file:
-Dcoldfusion.dotnet.disableautoconversion=true
For an example of using the function, see DotNetToCFType in the CFML Reference.
Using .NET objects
.NET fields and return values with class types are available in ColdFusion as .NET objects. You can use the objects
methods to access object data and make it available to ColdFusion using supported data types.
The following example gets information about a systems drives. It calls the System.IO.DriveInfo.GetDrives() method
to get an array of System.IO.DriveInfo objects, one per drive. It then calls the object methods to get specific
information about the drives, and displays the information. The example uses a cfdump tag to simplify the code.
Note: The System.IO.DriveInfo is not included in the .NET 1.x framework. It is included in .NET 2.0 and later
frameworks. For information on determining the .NET framework, see Determining and changing the .NET version on
page 1170.
1164
You cannot invoke methods with pointers as arguments or the return type.
You cannot invoke methods that take Out parameters.
ColdFusion can only convert from System.Data.DataTable, System.Collection.Hashtable and
System.Collection.ArrayList to ColdFusion data types. ColdFusion cannot convert from ColdFusion queries,
structures, and arrays to these System data types; however, it can convert from ColdFusion arrays to the CLR array
type. Therefore, you cannot pass structures or queries directly to .NET methods.
If the JavaCast function cannot eliminate ambiguity between functions with the same number of parameters
because a single Java type corresponds to multiple .NET types, ColdFusion creates a single proxy that uses the .NET
data type that corresponds directly to a Java type.
For more information on how to ambiguous handle type conversions, see Converting between .NET and
ColdFusion data types on page 1157.
1165
Assemblies registered in the DotNetSide.exe.config file must have unique class names. If two or more assemblies
have the same class name, method invocation can result in an error or can give the wrong result. For example, do
not have two DLLs, a.dll and b.dll, that contain the same class name, nam1.name2.MyClass. If you use one DLL and
later want to use another DLL that contains a class that clashes with first, restart the ColdFusion .NET Service if
ColdFusion and .NET both are on the same machine. If they are on the different machines, remove the entry for
the first DLL from the DotNetSide.exe.config file and restart the ColdFusion .NET Service on the Windows
machine hosting the .NET service.
Example applications
The first application example uses a Microsoft .NET system class method directly. The second application example
uses a custom C# class to access Microsoft Word.
1166
<cfset filename="C:\dotNet\demo.doc">
<cfif fileexists(filename)>
<cffile action="delete" file="#filename#">
</cfif>
<cfobject type=".NET" assembly="C:\dotNetApp\WordApp.dll,C:\dotNet\Interop.Office.dll"
name="wordCreator" class="WordApp.WordCreator">
<cfset wordCreator.init("#filename#")>
<cfdump label="WordCreator Class Dump" var="#wordCreator#">
<cfset someText = "ColdFusion created this sample document using Windows .NET class methods.
The text is long enough to appear in the Word file on multiple lines.">
<cfloop from=1 to=5 index =i>
<cfset wordCreator.addText(someText)>
<cfset wordCreator.newParagraph()>
<cfset wordCreator.newParagraph()>
<cfset wordCreator.addText("Starting a new paragraph. It starts a
a new line.")>
<cfset wordCreator.newParagraph()>
<cfset wordCreator.newParagraph()>
</cfloop>
<cfset wordCreator.save()>
System;
System.IO;
System.Collections.Generic;
System.Text;
1167
Advanced tools
Occasionally, the use of additional tools for generating proxies and running the .NET extension software can be helpful
in some workflows.
For example:
jnbproxy /al C:\dotNet\netdll\PrimitiveTypes.dll /d C:\dotNet\MyJavajars
/host localhost /n PrimitiveTypes /nj /pd j2n /port 6085 /pro b
/pp C:\ColdFusion8\lib CSharpDatatypes.PrimitiveTypes
Options
The following table lists the options that you can use. To create proxies on a system that is running ColdFusion, use
the /nj option and do not specify the /bp, /java, or /jp options.
1168
Option
Req/Opt
/al assemblylist
Required
/bp bcelpath
Optional
/cf
Required
/d directory
Optional
/f classfile
Optional
Default
Description
Specifies a semicolon-separated series of file paths of .NET assemblies
(DLL and EXE files) that contain the required .NET classes.
Specifies the path to the folder that contains the bcel.jar file.
Ignored if you use the /nj option.
Use the ColdFusion software license. If you do not include this option,
your proxies are limited to a 30-day trial period.
Specifies the directory in which to write a JAR file with the generated
proxies.
Reads the classes from the specified text file, not the command line.
For more information, see the JNBridge documentation.
/h
Optional
Lists the options and usage information. Typing the command jnbproxy
with no options or arguments results in the same information.
/host hostname
Required
Specifies the host on which the .NET code is located. This option can be a
host name or an IP address. Normally, you specify localhost.
/java javapath
Optional
/jp jnbcorepath
Optional
/ls
Optional
Lists all classes that are generated in support of the specified classes (see
Supporting classes on page 1153), but don't generate the proxies.
/n name
Optional
Specifies the name of the JAR file in which to place the proxies. Do not
specify the .jar extension; the tool automatically adds it.
/nj
Optional
Does not start Java automatically. If you use this option, Java must be
running, and the /bp, /java, /jp, and /wd options, if present, are
ignored.
/ns
Optional
Generates proxies for the classes specified on the command line (or class
file) only, not for any supporting classes.
/pd
Required
/port portNum
Required
Specifies the port on which the .NET side listens when generating the
proxies. Must be an integer. Normally this value is 6085.
/pro protocol
Required
/wd dir
optional
TCP/binary
(HTTP/SOAP
Classes
A space-separated sequence of fully qualified .NET class names (for example, CSharpDatatypes.PrimitiveTypes)
for which to generate proxies. The proxies for System.Object and System.Type are always generated, even if they are
not listed in the class list.
1169
In general, use reference proxies (the default), because they maintain the normal parameter-passing semantics of
Java and C#.
1170
4 Repeat steps 2 and 3 to select multiple groups of classes and set their passing methods.
5 Click OK.
If the function reports that the active version is not the one you require, install or reinstall the correct version of the
.NET framework redistributable package on the system that runs ColdFusion. Then reinstall the ColdFusion .NET
extension so that it uses the correct .NET version.
configuration, this directory is installDir\jnbridge. On a system with a stand-alone .NET extension installation, or
a J2EE or multiserver configuration, it is in the .NETInstallDir\jnbridge directory, and the default installation
directory is C:\ColdFusonDotNetExtension.
3 Enter the following command:
JNBDotNetSide
1171
About objects
COM and CORBA are two of the object technologies supported by ColdFusion. Other object technologies include Java
and ColdFusion components. For more information on ColdFusion components see Building and Using ColdFusion
Components on page 177.
An object is a self-contained module of data and its associated processing. An object is a building block that you can
together with other objects and integrate into ColdFusion code to create an application.
A handle, or name, represents an object. Objects have properties that represent information. Objects also provide
methods for manipulating the object and getting data from it. The exact terms and rules for using objects vary with the
object technology.
You create instances of objects using the cfobject tag or the CreateObject function. You then use the object and its
methods in ColdFusion tags, functions, and expressions. For more information on the ColdFusion syntax for using
objects, see Creating and using objects on page 1172.
About CORBA
CORBA (Common Object Request Broker Architecture) is a distributed computing model for object-oriented
applications defined by the Object Management Group (OMG). In this model, an object is an encapsulated entity
whose services are accessed only through well-defined interfaces. The location and implementation of each object is
hidden from the client requesting the services. ColdFusion supports CORBA 2.3 on both Windows and UNIX.
CORBA uses an Object Request Broker (ORB) to send requests from applications on one system to objects executing
on another system. The ORB allows applications to interact in a distributed environment, independent of the
computer platforms on which they run and the languages in which they are implemented. For example, a ColdFusion
application running on one system can communicate with an object that is implemented in C++ on another system.
CORBA follows a client-server model. The client invokes operations on objects that the server manages, and the server
replies to requests. The ORB manages the communications between the client and the server using the Internet InterORB Protocol (IIOP).
Each CORBA object has an interface that is defined in the CORBA Interface Definition Language (IDL). The CORBA
IDL describes the operations that can be performed on the object, and the parameters of those operations. Clients do
not have to know anything about how the interface is implemented to make requests.
To request a service from the server, the client application gets a handle to the object from the ORB. It uses the handle
to call the methods specified by the IDL interface definition. The ORB passes the requests to the server, which
processes the requests and returns the results to the client.
For information about CORBA, see the following OMG website, which is the main web repository for CORBA
information: www.omg.com.
1172
Creating objects
You create, or instantiate (create a named instance of) an object in ColdFusion with the cfobject tag or
CreateObject function. The specific attributes or parameters that you use depend on the type of object you use, and
are described in detail in Creating and using COM objects on page 1174 and Creating CORBA objects on
page 1184. The following examples use a cfobject tag to create a COM object and a CreateObject function to create
a CORBA object:
<cfobject type="COM" action="Create" name="obj" class="sample.MyObject">
obj = CreateObject("CORBA", "d:\temp\tester.ior", "IOR", "Visibroker")
ColdFusion releases any object created by cfobject or CreateObject, or returned by other objects, at the end of the
ColdFusion page execution.
Using properties
Use standard ColdFusion statements to access properties as follows:
1 To set a property, use a statement or cfset tag, such as the following:
<cfset obj.property = "somevalue">
As shown in this example, you do not use parentheses on the right side of the equation to get a property value.
Calling methods
Object methods usually take zero or more arguments. You send In arguments, whose values are not returned to the
caller by value. You send Out and In,Out arguments, whose values are returned to the caller, by reference. Arguments
sent by reference usually have their value changed by the object. Some methods have return values, while others do not.
Use the following techniques to call methods:
If the method has no arguments, follow the method name with empty parentheses, as in the following cfset tag:
<cfset retVal = obj.Method1()>
If the method has one or more arguments, place the arguments in parentheses, separated by commas, as in the
following example, which has one integer argument and one string argument:
<cfset x = 23>
<cfset retVal = obj.Method1(x, "a string literal")>
If the method has reference (Out or In,Out) arguments, use double quotation marks (") around the name of the
variable you are using for these arguments, as shown for the variable x in the following example:
<cfset x = 23>
<cfset retVal = obj.Method2("x","a string literal")>
<cfoutput> #x#</cfoutput>
1173
In this example, if the object changes the value of x, it now contains a value other than 23.
or
<cfset objX = myObj.X>
<cfset prop = objX.Property>
COM requirements
To use COM components in your ColdFusion application, you need at least the following items:
The COM objects (typically DLL or EXE files) that you want to use in your ColdFusion application pages. Ensure
that these components implement the IDispatch interface, and therefore allow late binding.
Microsoft OLE/COM Object Viewer, available from Microsoft. This tool lets you view registered COM objects.
Object Viewer lets you view the class information of an object so that you can properly define the class attribute
for the cfobject tag. It also displays the interfaces the object supports, so you can discover the properties and
methods (for the IDispatch interface) of the object.
You typically register Local servers (.exe files) either by starting them or by specifying a command-line parameter, such
as the following:
C:\pathname\servername.exe -register
1174
Public methods
Put properties
Get properties
The method and property information include the parameter or property types and whether they are in, out, optional,
or retval values. The cfdump tag output does not include the ProgID of the object.
Note: The dump header indicates the ColdFusion object class, which is coldfusion.runtime.com.ComProxy, and the COM
object CLSID.
Using the OLE/COM Object Viewer
The OLE/COM Object Viewer installation installs the executable, by default, as \mstools\bin\oleview.exe. You use the
Object Viewer to retrieve a COM object ProgID, as well as its methods and properties.
To find an object in the Object Viewer, it must be registered, as described in Registering the object on page 1173. The
Object Viewer retrieves all COM objects and controls from the Registry, and presents the information in a simple
format, sorted into groups for easy viewing.
By selecting the category and then the component, you can see the ProgID of a COM object. The Object Viewer also
provides access to options for the operation of the object.
To view object properties:
1 Open the Object Viewer and scroll to the object that you want to examine.
2 Select and expand the object in the left pane of the Object Viewer.
3 Right-click the object to view it, including the TypeInfo.
If you view the TypeInfo, you see the object methods and properties. Some objects do not have access to the
TypeInfo area, which is determined when an object is built and by the language used.
The following line shows how to use the corresponding CreateObject function in CFScript:
Mailer = CreateObject("COM", "CDONTS.NewMail");
1175
You use these properties to define elements of your mail message. The CDO for NTS NewMail object also includes a
send method which has optional arguments to send messages.
on the server.
You can use the optional cfobjectcontext attribute to specify the object context. If you do not specify a context,
ColdFusion uses the setting in the Registry. The following table describes the context attribute values:
Attribute value
Description
InProc
An in-process server object (typically a DLL) that is running in the same process space as the calling
process, such as ColdFusion.
local
An out-of-process server object (typically an EXE file) that is running outside the ColdFusion process space
but running locally on the same server.
remote
An out-of-process server object (typically an EXE file) that is running remotely on the network. If you
specify remote, Also use the server attribute to identify where the object resides.
1176
Note: Use the cftry and cfcatch tags to handle exceptions thrown by COM objects. For more information on exception
handling, see Handling runtime exceptions with ColdFusion tags on page 287.
Releasing COM objects
By default, COM object resources are released when the Java garbage collector cleans them. You can use the
ReleaseCOMObject function to immediately release resources if an object is no longer needed.
Use the ReleaseCOMObject function to release COM objects that are launched as an external process, such as
Microsoft Excel. The garbage collector does not always clean these processes in a short time, resulting in multiple
external processes running, which drains system resources.
If the COM object has an end method, such as a quit method that terminates the program, call this method before you
call the ReleaseComObject function. If you use the ReleaseComObject function on an object that is in use, the object
is prematurely released and your application gets exceptions.
Example
The following example creates a Microsoft Excel application object, uses it, then releases the object when it is no longer
needed:
<h3>ReleaseComObject Example</h3>
<cfscript>
obj = CreateObject("Com", "excel.application.9");
//code that uses the object goes here
obj.quit();
ReleaseComObject(obj);
</cfscript>
1177
The string "Hello Object" is passed to the object's calculate method as an input argument. The method sets the value
of outNumericArg to a numeric value.
Understanding common COM-related error messages
The following table described some error messages you could encounter when using COM objects:
1178
Error
Cause
The COM object is not registered or does not exist. This error usually
occurs when an object existed previously, but was removed.
The COM object was instantiated correctly, but the method you
specified does not exist.
Unknown name.
Dynamic discovery takes time and can reduce server performance with frequently used complex COM objects.
Dynamic discovery uses the IDispatcher interface to determine the COM object features, and does not always
handle some complex COM interfaces.
To overcome these problems, ColdFusion includes a utility, com2java.exe, that creates static Java stub proxy classes
for COM objects. ColdFusion can use these Java stubs to access COM objects more efficiently than when it creates the
proxies dynamically. Additionally, the com2java.exe utility can create stubs for features that the dynamic proxy
generator could miss.
ColdFusion ships with pregenerated stubs for the Windows XP, Windows 2000, and Windows 97 editions of Microsoft
Excel, Microsoft Word, and Microsoft Access. ColdFusion is configured to automatically use these stubs.
If you create Java stub files for a COM object, you continue to use the cfobject tag with a type attribute value of COM,
or the CreateObject function with a first argument of COM, and you access the object properties and methods as you
normally do for COM objects in ColdFusion.
Use the following steps to use the com2java.exe utility. This procedure uses Microsoft Outlook as an example.
To create Java stub files for COM objects:
1 Configure your system as follows:
a Ensure that a JDK (Java Development Kit) is correctly installed, including proper configuration of the
This directory can be temporary. You add files from the directory to a ColdFusion JAR file.
1179
3 Run the CF_root\Jintegra\bin\com2java.exe program from a command line or the Windows Start Menu. A window
appears.
a If a COM class implements multiple interfaces that define methods with the same names, click the Options
button and clear the Implement interfaces that may conflict option. The generated Java stub classes do not
implement the additional, conflicting, interfaces. You can still access the interfaces using the getAsXXX method
that is generated. See the generated comments in the Java files.
b Click the Select button.
c Select your COM objects Type Library or DLL. For Microsoft Outlook in Windows XP, it is normally Program
Files\Microsoft Office\Office10\MSOUTL.OLB.
d Enter a package name (for example, outlookXP) in the Java package field in the com2java dialog box. This
package will contain all the classes for the Java stubs for the COM object.
Note: Adobe uses a package name that starts with coldfusion.runtime.com.com2java for the packages that contain
the preinstalled Java stubs for Microsoft Excel, Microsoft Word, and Microsoft Access. For example, the name for
the package containing the Microsoft Word XP Java stub classes is coldfusion.runtime.com.com2java.wordXP.
This package name hierarchy results in the wordXP classes having a path inside the msapps.jar file of
coldfusion\runtime\com\com2java\wordXP\className.class. Although this naming convention is not necessary,
consider using a similar package naming convention for clarity, if you use many COM objects.
e Click the Generate Proxies button to display the File browser. Select the directory you created in step 2., and click
The compiler switches ensure that you have enough memory to compile all the necessary files.
Note: If you did not place jintegra.jar on your CLASSPATH in step 1b, add the switch classpath:/cf_root/lib/jintegra.jar, where cf_rootis the directory where ColdFusion is installed, to the
command.
5 Ensure that the ColdFusion server is not running. To stop the ColdFusion server, open the Services control panel,
working directory. In this example, make c:\src your working director by entering cd .. in the Command prompt
from step 4.
b Enter the following command:
jar -uvf cf_root\lib\msapps.jar directoryName\*.class
1180
Where cf_root is the directory where ColdFusion is installed and directoryName is the name of the directory that
contains the class files. For the OutlookXP example, enter the following line:
jar -uvf C:\CFusion\lib\msapps.jar outlookXP\*.class
7 Update the cf_root /lib/neo-comobjmap.xml file by appending your object definition to the list. The object
Microsoft applications, this class is Application. In general, the largest class file created in step 4 is the main class.
For example, to add outlookXP to neo-comobjmap.xml, add the lines in bold text above the </struct> end tag:
<var name="access.application.9">
<string>coldfusion.runtime.com.com2java.access2k.Application</string>
</var>
<var name="outlook.application.10">
<string>outlookXP.Application</string>
</var>
</struct>
In this example, outlook.application.10 is the ProgID of the Outlook COM object, outlookXP is the package name
you specified in step 3c, and Application is the main class of the COM object.
8 Restart the ColdFusion server: Open the Services control panel, select ColdFusion application server, and click
Start.
9 After you have installed the stubs, you can delete the directory you created in step 2., including all its contents.
The COM object need not be created for every request or session. (For session-specific objects, consider using the
technique described here with the Session scope in place of the Application scope.)
For best performance, make the object multi-threaded. Otherwise, only one request can access the object at a time.
1181
Lock the code that accesses and modifies common data. In general, you do not have to lock code that modifies a
shared objects data, including writable properties or file contents, if multiple requests do not share the data (as
opposed to the object) . However, specific locking needs depend on the COM objects semantics, interface, and
implementation.
All cflock tags in the application that use an Application scope lock share one lock. Therefore, code that accesses
a frequently used COM object inside an Application scope lock can become a bottleneck and reduce throughput if
many users request pages that use the object. In some cases, you can avoid some contention by placing code that
uses the COM object in named locks. Place the code that creates the object in an Application scope lock.
Note: You can also improve the performance of some COM objects by creating Java stubs, as described in Accessing
Complex COM Objects using Java proxies on page 1178. Using a Java stub does not improve performance as much as
sharing the COM object, but the technique works with all COM objects. Also, generate Java stubs to correctly access
complex COM objects that do not properly make all their features available through the COM IDispatcher interface.
Therefore, to get the greatest performance increase and prevent possible problems, use both techniques.
Example 1: Using the FileSystem object
The following example uses the Microsoft FileSystem Scripting object in the Application scope. This code creates a
user-defined function that returns a structure that consists of the drive letters and free disk space for all hard drives on
the system.
<cfapplication name="comtest" clientmanagement="No" Sessionmanagement="yes">
<!--- Uncomment the following line if you must delete the object from the
Application scope during debugging. Then restore the comments.
This technique is faster than stopping and starting the ColdFusion server. --->
<!--- <cfset structdelete(Application, "fso")> --->
<!--- The getFixedDriveSpace user-defined function returns a structure with
the drive letters as keys and the drive's free space as data for all fixed
drives on a system. The function does not take any arguments --->
<cffunction name="getFixedDriveSpace" returnType="struct" output=True>
<!--- If the FileSystemObject does not exist in the Application scope,
create it. --->
<!--- For information on the use of initialization variables and locking in
this code, see "Locking application variables efficiently" in Chapter 15,
"Using Persistent Data and Locking" --->
<cfset fso_is_initialized = False>
<cflock scope="application" type="readonly" timeout="120">
<cfset fso_is_initialized = StructKeyExists(Application, "fso")>
</cflock>
<cfif not fso_is_initialized >
<cflock scope="Application" type="EXCLUSIVE" timeout="120">
<cfif NOT StructKeyExists(Application, "fso")>
<cfobject type="COM" action="create" class="Scripting.FileSystemObject"
name="Application.fso" server="\\localhost">
</cfif>
</cflock>
</cfif>
<!--- Get the drives collection and loop through it to populate the
1182
structure. --->
<cfset drives=Application.fso.drives()>
<cfset driveSpace=StructNew()>
<cfloop collection="#drives#" item="curDrive">
<!--- A DriveType of 2 indicates a fixed disk --->
<cfif curDrive.DriveType IS 2>
<!--- Use dynamic array notation with the drive letter for the struct key
--->
<cfset driveSpace["#curDrive.DriveLetter#"]=curDrive.availablespace>
</cfif>
</cfloop>
<cfreturn driveSpace>
</cffunction>
<!--- Test the function. Get the execution time for running the function --->
<cfset start = getTickCount()>
<cfset DriveInfo=getFixedDriveSpace()>
<h3>Getting fixed drive available space</h3>
<cfoutput>Execution Time: #int(getTickCount()-start)# milliseconds</cfoutput><br><br>
<cfdump label="Drive Free Space" var="#driveInfo#">
1183
<cfobject type="com"
action="Create"
class="Word.application"
name="Application.MyWordobj"
context="local">
</cfcatch>
</cftry>
<cfset Application.mywordobj.visible = False>
</cfif>
</cflock>
</cfif>
<!--- Convert a Word document in temp.doc to an HTML file in temp.htm. --->
<!--- Because this example uses a fixed filename, multiple pages could try
to use the file simultaneously. The lock ensures that all actions from
reading the input file through closing the output file are a single "atomic"
operation, and the next page cannot access the file until the current page
completes all processing.
Use a named lock instead of the Application scope lock to reduce lock contention. --->
<cflock name="WordObjLock" type="exclusive" timeout="120">
<cfset docs = application.mywordobj.documents()>
<cfset docs.open("c:\CFusion\wwwroot\temp.doc")>
<cfset converteddoc = application.mywordobj.activedocument>
<!--- Val(8) works with Word 2000. Use Val(10) for Word 97 --->
<cfset converteddoc.saveas("c:\CFusion\wwwroot\temp.htm",val(8))>
<cfset converteddoc.close()>
</cflock>
<cfoutput>
Conversion of temp.htm Complete<br>
Execution Time: #int(getTickCount()-start)# milliseconds<br>
</cfoutput>
1184
Description
type
context
Specifies the CORBA binding method, that is, how the object is obtained, as follows:
class
IOR
NameService
Specifies the information required for the binding method to access the object.
If you set the context attribute to IOR, The class attribute must be to the full path of a file containing the string
version of the IOR. ColdFusion must be able to read this IOR file at all times, so make it local to the server or locate
it on the network in an accessible place.
If you set the context attribute to NameService, The class attribute must be a name delimited by forward
slashes (/), such as MyCompany/Department/Dev. You can use period-delimited kind identifiers as part of the
class attribute; for example, adobe.current/Eng.current/CF"
name
Specifies the name (handle) that your application uses to call the object's interface.
locale
(Optional) Identifies the connector configuration. You can omit this option if ColdFusion Administrator has only
one connector configuration, or if it has multiple connector configurations and you want to use the one that is
currently selected in the Administrator. If you specify this attribute, it must be an ORB name you specified in the
CORBA Connector ORB Name field when you configured a CORBA connector in ColdFusion Administrator; for
example, Visibroker.
For example, use the following CFML to invoke a CORBA object specified by the tester.ior file if you configured your
ORB name as Visibroker:
<cfobject action = "create" type = "CORBA" context = "IOR"
class = "d:\temp\tester.ior" name = "handle" locale = "Visibroker">
When you use the CreateObject function to invoke this CORBA object, specify the name as the function return
variable, and specify the type, class, context, and locale as arguments. For example, the following line creates the same
object as the preceding cfobject tag:
handle = CreateObject("CORBA", "d:\temp\tester.ior", "IOR", "Visibroker")
1185
You use the handle name to invoke all of the interface methods, as in the following CFML:
<cfset ret=myHandle.method(foo)>
However, ColdFusion cannot differentiate between the two methods. If you call either method, you cannot be sure
which of the two gets invoked.
Passing parameters by value (in parameters)
CORBA in parameters are always passed by value. When calling a CORBA method with a variable in ColdFusion,
specify the variable name without quotation marks, as shown in the following example:
IDL
CFML
CFML
In this case, the ColdFusion variable foo corresponds to the inout parameter b. When the CFML executes, the
following happens:
1 ColdFusion calls the method, passing it the variable by reference.
2 The CORBA method replaces the value passed in, "My Initial String", with some other value. Because the variable
was passed by reference, this action modifies the value of the ColdFusion variable.
1186
3 The cfoutput tag prints the new value of the foo variable.
CFML
<cfset foo=3.1415>
<cfset ret=handle.method("foo")>
<cfoutput>#ret#</cfoutput>
General support
As parameters
As return value
constants
No
No
No
attributes
NA
NA
enum
Yes
Yes
union
No
No
No
sequence
Yes
Yes
Yes
array
Yes
Yes
Yes
interface
Yes
Yes
Yes
typedef
Yes
NA
NA
struct
Yes
Yes
Yes
module
Yes
NA
NA
exception
Yes
NA
NA
any
No
No
No
boolean
Yes
Yes
Yes
char
Yes
Yes
Yes
wchar
Yes
Yes
Yes
string
Yes
Yes
Yes
wstring
Yes
Yes
Yes
octet
Yes
Yes
Yes
short
Yes
Yes
Yes
long
Yes
Yes
Yes
float
Yes
Yes
Yes
1187
General support
As parameters
As return value
double
Yes
Yes
Yes
unsigned short
Yes
Yes
Yes
unsigned long
Yes
Yes
Yes
longlong
No
No
No
unsigned longlong
No
No
No
void
Yes
NA
Yes
ColdFusion type
boolean
Boolean
char
One-character string
wchar
One-character string
string
String
wstring
String
octet
One-character string
short
Integer
long
Integer
float
Real number
double
Real number
unsigned short
Integer
unsigned long
Integer
void
struct
Structure
enum
array
sequence
Array
interface
An object reference
module
exception
attribute
1188
True
"yes", "true", or 1
False
"no", "false", or 0
You can use any of these values with CORBA methods that take Boolean parameters, as the following code shows:
IDL
module Tester
{
interface TManager
{
void testBoolean(in boolean a);
void testOutBoolean(out boolean a);
void testInoutBoolean(inout boolean a);
boolean returnBoolean();
}
}
CFML
module Tester
{
enum EnumType {a, b, c};
interface TManager
{
void testEnum(in EnumType a);
void testOutEnum(out EnumType a);
void testInoutEnum(inout EnumType a);
EnumType returnEnum();
}
}
CFML
In this example, the CORBA object gets called with the second (not first) entry in the enumerator.
Double-byte character considerations
If you are using an ORB that supports CORBA later than version 2.0, you do not have to do anything to support
double-byte characters. Strings and characters in ColdFusion convert appropriately to wstring and wchar data when
they are used. However, the CORBA 2.0 IDL specification does not support the wchar and wstring types, and uses the
8-bit Latin-1 character set to represent string data. In this case, you cannot pass parameters containing those
characters, however, you can call parameters with char and string types using ColdFusion string data.
1189
Handling exceptions
Use the cftry and cfcatch tags to catch CORBA object method exceptions thrown by the remote server, as follows:
1 Specify type="coldfusion.runtime.corba.CorbaUserException" in the cfcatch tag to catch CORBA
exceptions.
2 Use the cfcatch.getContents method to get the contents of the exception object.
The cfcatch.getContents method returns a ColdFusion structure containing the data specified by the IDL for the
exception.
The following code example shows the IDL for a CORBA object that raises an exception defined by the
PrimitiveException exception type definition, and the CFML that catches the exception and displays the contents of
the object.
IDL
interface myInterface
{
exception PrimitiveException
{
long l;
string s;
float f;
};
void testPrimitiveException() raises (PrimitiveException);
}
CFML
<cftry>
<cfset ret0 = handle.testPrimitiveException()>
<cfcatch type=coldfusion.runtime.corba.CorbaUserException>
<cfset exceptStruct= cfcatch.getContents()>
<cfdump var ="#exceptStruct#">
</cfcatch>
</cftry>
CORBA example
The following code shows an example of using a LoanAnalyzer CORBA object. This simplified object determines
whether an applicant is approved for a loan based on the information that is supplied.
The LoanAnalyzer CORBA interface has one method, which takes the following two in arguments:
An Account struct that identifies the applicants account. It includes a Person struct that represents the account
holder, and the applicants age and income.
A CreditCards sequence, which corresponds to the set of credit cards the user currently has. A member of the
CardType enumerator represents the credit card type. (This example assumes that the applicant has no more than
one of any type of card.)
The object returns a Boolean value indicating whether the application is accepted or rejected.
1190
CFML
1191
1192
End users of your application are not required to wait for SMTP processing to complete before a page returns to
them. This design is especially useful when a user action causes the sending of more than a handful of messages.
Messages sent using cfmail are delivered reliably, even in the presence of unanticipated events like power outages
or server crashes.
You can set how frequently ColdFusion checks for spooled mail messages on the Mail page in the ColdFusion
Administrator. If ColdFusion is busy or has a large existing queue of messages, however, delivery can occur after the
spool interval.
Some ColdFusion editions have advanced spooling options that let you fine-tune how ColdFusion sends mail. For
more information, see Configuring and Administering ColdFusion.
1193
In Windows: \CFusion\Mail\Undelivr
On UNIX: /opt/coldfusion/mail/undelivr
The error log entry that corresponds to the undelivered message contains the name of the file written to the UnDelivr
(or undelivr) directory.
Note: To have ColdFusion try to resend a message that it could not deliver, move the message file from the Undelivr
directory to the Spool directory.
For more information about the mail logging settings in the ColdFusion Administrator, see Configuring and
Administering ColdFusion.
to configure and optimize ColdFusion mail behavior. Select these options as appropriate.
7 Click Submit Changes.
ColdFusion saves the settings. The page displays a message indicating success or failure for connecting to the server.
ColdFusion Enterprise edition includes additional mail spooling and delivery features. For more information on these
features, and for information on the ColdFusion Administrator mail settings, see Configuring and Administering
ColdFusion.
Description
subject
from
1194
Attribute
Description
to
The e-mail address of the recipient. Use a comma-delimited list to specify multiple recipients.
cc
(Optional) The e-mail address of a carbon copy recipient. The recipient address is visible to other recipients. Use
a comma-delimited list to specify multiple cc recipients.
bcc
(Optional) The e-mail address of a blind carbon copy recipient. The recipient address is not visible to other
recipients. Use a comma-delimited list to specify multiple bcc recipients.
2 Save the file as send_mail.cfm in the myapps directory under your web_root directory.
3 Open your browser and enter the following URL:
http://localhost:8500/myapps/[email protected]
(Replace [email protected] with your e-mail address.)
The page sends the e-mail message to you, through your SMTP server.
Note: If you do not receive an e-mail message, check whether you have configured ColdFusion to work with your SMTP
server; for more information, see Sending e-mail messages on page 1193.
The cfmail tag has many options that let you customize your mail or control how it is sent. For a description of all
attributes, including options to wrap mail text at a specified column, specify the mail character encoding, and specify
the mail server, user name, and password, see the cfmail description in the CFML Reference.
1195
Note: In the HTML version of the message, escape any number signs, such as those used to specify colors, by using two #
characters; for example, bgcolor="##C5D9E5".
Sending a mail message in which the data the user enters in an HTML form determine the recipient and contents
Using a query to send a mail message to a database-driven list of recipients
Using a query to send a customized mail message, such as a billing statement, to a list of recipients that is
dynamically populated from a database
1196
Description
<cfoutput>
#ProductRequests.FirstName#
#ProductRequests.LastName#
(#ProductRequests.Company#) #ProductRequests.EMailAddress#&##013;
</cfoutput>
1197
1198
1199
Code
Description
Retrieves all data from the Customers table into a query named
GetCustomers.
<cfmail query="GetCustomers"
from="[email protected]"
to="#GetCustomers.EMail#"
subject="Contact Info Verification">
Dear #GetCustomers.FirstName# -
......
Company Name: #GetCustomers.Company#
Contact: #GetCustomers.FirstName#
#GetCustomers.LastName#
Address:
#GetCustomers.Address1#
#GetCustomers.Address2#
#GetCustomers.City#, #GetCustomers.State#
#GetCustomers.Zip#
Phone: #GetCustomers.Phone#
Fax: #GetCustomers.Fax#
Home Page: #GetCustomers.HomePageURL#
To add digital signature to all the mails you send, instead of adding the attributes to the tag, specify the settings in the
Server Settings > Settings page of the ColdFusion Administrator.
The supported keystores are JKS and PKCS12.
Due to import control restrictions in various countries, the policy files (local_policy.jar and US_export_policy.jar)
support only limited cryptography. If the key strength exceeds the limit, you might encounter the error suggesting that
the keystore cannot be loaded. If you are from an eligible country, you can download the unlimited strength version of
the policy files and replace the default cryptography JAR files with them. The files are available on the Java SDK web site.
1200
<cfmail from="[email protected]"
to="[email protected]"
subject="Requested Files">
Jake,
Here are the files you requested.
Regards,
Dan
<cfmailparam file="c:\widget_launch\photo_01.jpg">
<cfmailparam file="c:\widget_launch\press_release.doc">
</cfmail>
Use a fully qualified system path for the file attribute of cfmailparam. The file must be located on a drive on the
ColdFusion server machine (or a location on the local network), not the browser machine.
The following example shows a simple mail message with an inline image. In this case, the image is located between
paragraphs, but you could include it directly inline with the text. To test this example, replace the cfmailto parameter
with a valid e-mail address and change the file parameter to the path to a valid image.
<cfmail type="HTML"
to = "[email protected]"
from = "[email protected]"
subject = "Sample inline image">
<cfmailparam file="C:\Inetpub\wwwroot\web.gif"
disposition="inline"
contentID="image1">
<P>There should be an image here</p>
<img src="cid:image1">
<p> This text follows the picture</p>
</cfmail>
1201
<cfmail from="[email protected]"
to="[email protected]"
subject="Requested Files">
<cfmailparam name="Reply-To" value="[email protected]">
Dan,
Thanks very much for the sending the widget press release and graphic.
I'm now the company's Widget Master and am accepting e-mail at
[email protected].
See you at Widget World 2002!
Jake
</cfmail>
Note: You can combine the two uses of cfmailparam within the same ColdFusion page. Write a separate cfmailparam
tag for each header and for each attached file.
If your site has generic mailboxes that more than one person reads ([email protected]), it can be more
efficient to construct a ColdFusion mail front end to supplement individual user mail clients.
In many applications, you can automate mail processing when the mail is formatted to serve a particular purpose;
for example, when subscribing to a list server.
1202
2 Determine which mail message components you must process: message header, message body, attachments, and
so on.
3 Decide whether you must store the retrieved messages in a database.
4 Decide whether to delete messages from the POP server after you retrieve them.
5 Incorporate the cfpop tag in your application and create a user interface for accessing a mailbox.
6 Build an application page to handle the output. Retrieved messages can include characters that do not display
The query includes one variable that the cfquery tag does not return: the UID variable contains the unique identifier
of the e-mail message file.
You can reference these properties in a cfoutput tag by prefixing the query variable with the query name in the name
attribute of cfpop:
<cfoutput>
This operation returned #Sample.RecordCount# messages.
</cfoutput>
date
from
1203
header (A string with all the mail header fields, including entries that have separate fields in the query object)
messageNumber (The sequential number of the message in the POP server; identical to the row number of the entry
in the query object)
2 Edit the following lines so that they use valid values for your POP mail server, user name, and password:
<cfpop server="mail.company.com"
username=#myusername#
password=#mypassword#
3 Save the file as header_only.cfm in the myapps directory under your web_root and view it in your web browser:
This code retrieves the message headers and stores them in a cfpop recordset called Sample. For more information
about working with recordset data, see Using Query of Queries on page 428.
1204
The HTMLCodeFormat function replaces characters that have meaning in HTML, such as the less than (<) and greater
than (>) signs that can surround detailed e-mail address information, with escaped characters such as < and >.
In addition, you can process the date returned by cfpop with the ParseDateTime function, which accepts an argument
for converting POP date/time objects into a CFML date-time object.
You can reference any of these columns in a cfoutput tag, as the following example shows:
<cfoutput>
#ParseDateTime(queryname.date, "POP")#
#HTMLCodeFormat(queryname.from)#
#HTMLCodeFormat(queryname.messageNumber)#
</cfoutput>
Retrieving messages
When you use the cfpop tag with action="GetAll", ColdFusion returns the same columns as with getheaderonly,
plus the following additional columns:
body
htmlbody
textbody
If the message is multipart, the htmlbody and textbody fields contain the contents of the HTML and plain text parts,
and the body field has the first part in the message. If the message has only one part, the body contains the message,
and either the htmlbody or textbody field, depending on the message type, also has a copy of the message.
Retrieve entire messages
1 Create a ColdFusion page with the following content:
1205
<html>
<head><title>POP Mail Message Body Example</title></head>
<body>
<h2>This example adds retrieval of the message body:</h2>
<cfpop server="mail.company.com"
username=#myusername#
password=#mypassword#
action="GetAll"
name="Sample">
<cfoutput query="Sample">
MessageNumber: #HTMLEditFormat(Sample.messageNumber)# <br>
To: #Sample.to# <br>
From: #HTMLEditFormat(Sample.from)# <br>
Subject: #HTMLEditFormat(Sample.subject)# <br>
Date: #HTMLEditFormat(Sample.date)#<br>
Cc: #HTMLEditFormat(Sample.cc)# <br>
ReplyTo: #HTMLEditFormat(Sample.replyTo)# <br>
<br>
Body:<br>
#Sample.body#<br>
<br>
Header:<br>
#HTMLCodeFormat(Sample.header)#<br>
<hr>
</cfoutput>
</body>
</html>
2 Edit the following lines so that they use valid values for your POP mail server, user name, and password:
<cfpop server="mail.company.com"
username=#myusername#
password=#mypassword#
3 Save the file as header_body.cfm in the myapps directory under your web_root and view it in your web browser:
This example does not use a CFML function to encode the body contents. As a result, the browser displays the
formatted message as you would normally see it in a mail program that supports HTML messages.
1206
2 Edit the following lines so that they use valid values for your POP mail server, user name, and password:
<cfpop server="mail.company.com"
username=#myusername#
password=#mypassword#
3 Save the file as header_body_att.cfm in the myapps directory under your web_root and view it in your web browser:
Note: To avoid duplicate filenames when saving attachments, set the generateUniqueFilenames attribute of cfpop to Yes.
Deleting messages
Using the cfpop tag to delete a message permanently removes it from the server. By default, retrieved messages remain
on the POP mail server. To delete the messages, set the action attribute of the cfpop tag to Delete. Use the
messagenumber attribute to specify the messages to delete; omit the attribute to delete all the users messages from the
server.
1207
Note: Message numbers are reassigned at the end of every POP mail server communication that contains a delete action.
For example, if you retrieve four messages from a POP mail server, the server returns the message numbers 1,2,3,4. If you
delete messages 1 and 2 with a single cfpop tag, messages 3 and 4 are assigned message numbers 1 and 2, respectively.
Delete messages
1 Create a ColdFusion page with the following content:
<html>
<head>
<title>POP Mail Message Delete Example</title>
</head>
<body>
<h2>This example deletes messages:</h2>
<cfpop server="mail.company.com"
username=#username#
password=#password#
action="Delete"
messagenumber="1,2,3">
</body>
</html>
2 Edit the following lines so that they use valid values for your POP mail server, user name, and password:
<cfpop server="mail.company.com"
username=#myusername#
password=#mypassword#
3 Save the file as message_delete.cfm in the myapps directory under your web_root and view the file in your web
browser.
4 Run the header_only.cfm page that you created to confirm that the messages have been deleted.
Important: When you view this page in your web browser, ColdFusion immediately deletes the messages from the POP
server.
Actions
Mail messages
get, get attachments, get meeting information, move to a different folder, delete, delete attachments, set
properties
1208
Item
Actions
Calendar events
Contacts
Tasks
Purpose
cfexchangeconnection
Opens and closes persistent connections between an application and the Exchange server.
Gets information about subfolders of the Inbox.
cfexchangecalendar
cfexchangecontact
cfexchangemail
cfmail
cfexchangetask
cfexchangefilter
Specifies the criteria to get specific items. Used only as a child of the cfexchangecalendar,
cfexchangecontact, cfexchangemail, and cfexchangetask tags that specify the get action.
The following list describes a few of the activities you can do using ColdFusion with the Exchange server:
A persistent connection lasts until you explicitly close it. Persistent connections let you use a single connection for
multiple tasks, which saves the processing overhead of opening and closing a separate connection for each
interaction with the Exchange server.
A transient connection lasts for the duration of the tag that interacts with the Exchange server. Transient
connections are a useful technique on ColdFusion pages where you only have to access the Exchange server for a
single tag; for example, where you only get a set of contacts.
1209
The Exchange server, Exchange access, and WebDav access are configured in IIS.
The Exchange server enables Outlook web access to all login users.
If you are using HTTPS to log into the exchange server, you have a valid client certificate in the JRE certificate store.
Ensure that IIS is configured for access to the Exchange server
1 Open the IIS manager from the Administrative Tools control panel on the machine where the Exchange server is
installed.
2 Expand the Web Sites node in the tree on the left pane. If you see Exchange there, the web application is configured
for Exchange. If you do not see it, follow the Microsoft instructions for configuring Exchange in the website
3 Click the Web Service Extension node in the tree on the left pane. The right pane shows Web Service Extensions
and their status. Make sure that Microsoft Exchange Server and WebDav entries are both allowed. If either entry is
prohibited, select it and click the Allow button.
Enabling Outlook web access
To establish any connection, the Exchange server must grant the login user Outlook web access.
Check and grant web access
1 In the Exchange administrator, open Administrative Tools > Active Directory Users and Computers > your domain
name > users.
2 Right-click the user whose ID you use to establish connections.
3 Select the Exchange Features tab.
4 In the Protocols section, enable the Outlook Web Access entry if it is disabled.
panel.
2 In the tree on the left pane, expand the Web Sites node,
3 Right-click Exchange and ExchWeb in the expanded list and open the Web Site Properties dialog, then click the
1210
To install the certificate, run the following command using keytool.exe, which is in the jre\bin folder:
keytool.exe -importcert -file <path_to_certificate_file> -keystore ..\lib\security\cacerts
Note: The keytool.exe program requires you to enter a password. The default password is changeit.
1211
Specify the delegated users user name and password in the username and password attributes.
Specify the mailbox name of the account that you are accessing in the mailboxName attribute.
You can access the account in a cfexchangeconnection tag that opens a persistent connection, or in a ColdFusion
Exchange tag that uses a transient connection.
For example, if access rights to the docuser3 account are delegated to docuser4, you can use the
cfexchangeconnection tag as in the following example to open a connection to the docuser3 account by using
docuser4s credentials:
<cfexchangeconnection action="open"
connection="theConnection"
server="myexchangeserver.mycompany.com"
username="docuser4"
password="secret"
mailboxName="docuser3">
1212
You can use this connection for any activities that docuser3 has delegated to docuser4. If docuser3, for example, has
only delegated reviewer rights to the calendar, you can use this connection only with the cfexchangecalendar tag
with get and getAttachments attributes.
Attribute
cfexchangecalendar
event
cfexchangecontact
contact
cfexchangetask
task
Enclose in number signs (#) the variable that contains the details of the event, contact, or task data, as in the following
example:
<cfexchangecalendar action="create" connection="myConn" event="#theEvent#"
result="resultUID">
The contents of the entry information structure depend on the tag. For details of the structure contents, see
cfexchangecalendar, cfexchangecontact, and cfexchangetask in the CFML Reference.
Note: To create an Exchange calendar appointment, create a calendar event and do not specify any required or optional
attendees.
The following example lets a user enter information in a form and creates a contact on the Exchange server with the
information:
1213
<!--- If the form was submitted, fill the contact structure from it. --->
<cfif isDefined("Form.Submit")>
<cfscript>
sContact.FirstName=Form.firstName;
sContact.Company=Form.company;
sContact.LastName=Form.lastName;
sContact.BusinessAddress.Street=Form.street;
sContact.BusinessAddress.City=Form.city;
sContact.BusinessAddress.State=Form.state;
1214
sContact.BusinessAddress.Country=Form.country;
sContact.BusinessPhoneNumber=Form.businessPhone;
sContact.MobilePhoneNumber=Form.cellPhone;
sContact.BusinessFax=Form.fax;
sContact.Email1=Form.email;
</cfscript>
<!--- Create the contact in Exchange --->
<cfexchangecontact action="create"
username ="#user1#"
password="#password1#"
server="#exchangeServerIP#"
contact="#sContact#"
result="theUID">
<!--- Display a confirmation that the contact was added. --->
<cfif isDefined("theUID")>
<cfoutput>Contact Added. UID is#theUID#</cfoutput>
</cfif>
</cfif>
For another example of creating items, which creates a task, see Using transient connections on page 1211.
To get mail that is not directly in the Inbox, specify the path from the root of the mailbox to the mail folder, and
you can get items from only a single mail folder at a time. You can use the cfexchangeconnection tag to get the
names, paths, and sizes of all folders in a mailbox, and can use the results to iterate over the folders.
To get an attachment to an item, you must first get the item, and then use the item UID to get its attachments.
If an Exchange item contains a message with inline images, the images are available as attachments. You can get the
attachments, use the attachment CID to locate the image in the message, and display the image inline.
Note: The getattachment action does not always populate the CID field for HTML mail that contains inline
attachments, such as images. This problem occurs because some Exchange clients do not always set the CID values if
the attachments are sent inline.
folder name
full path from the mailbox to the folder, including the Inbox
folder size, in bytes
You can specify the folder whose subfolders you are getting and whether to recursively get all levels of subfolders.
1215
You can use a folder path from the getSubfolders action in the cfexchangemail tag folder attribute to specify the
folder that contains the mail message that requires action. If you do not specify a folder, the cfexchangemail tag
searches only the top level of the Inbox for the message on which to act.
To perform operations on mail from multiple folders, including getting mail items or attachments, you can loop over
the entries in the query returned by the getSubfolders action, as the following example shows. This example
generates a report of all declined meeting messages in the Inbox and all its subfolders.
<!--- Create a connection. --->
<cfexchangeConnection
action="open"
username ="#user2#"
password="#password2#"
server="#exchangeServerIP#"
connection="conn1">
<!--- Get the names and paths to all subfolders. --->
<cfexchangeconnection action="getSubfolders" connection="conn1"
name="folderInfo" folder="Inbox" recurse="yes">
<!--- Get the information from the Inbox top level.
The getSubfolders results do not include an Inbox row. --->
<cfexchangemail action="get" connection="conn1"
name="theResponses">
<cfexchangefilter name="MessageType" value="Meeting_Response">
</cfexchangemail>
<!--- Use a query of queries to select only the declined meetings. --->
<!--- You cannot use cfexchangefilter to filter for the meeting response type. --->
<cfquery dbtype="query" name="theResponses">
SELECT * FROM theResponses
WHERE MEETINGRESPONSE = 'Decline'
</cfquery>
<!--- Loop through the subfolders and get the meeting responses from each
folder. --->
<cfloop query="folderInfo">
<cfexchangemail action="get" connection="conn1"
name="#folderinfo.foldername#">
<cfexchangefilter name="folder" value="#folderinfo.folderpath#">
<cfexchangefilter name="MessageType" value="Meeting_Response">
</cfexchangemail>
<!--- Use the evaluate function to get the name of the folder. --->
<cfset meetingData=evaluate(folderinfo.foldername)>
<!--- Use a query of queries with a UNION clause to add this folder's
results to the theResponses query. --->
1216
Getting items
You get one or more events, contacts, mail messages, or tasks from the Exchange server by using a cfexchangecalendar,
cfexchangecontact, cfexchangemail, or cfexchangetask tag, respectively, and specifying an action attribute value of
get. ColdFusion returns the items in a query object that you specify in the name attribute. You determine the items to
get by specifying selection conditions in cfexchangefilter child tags. The code to get items from the Exchange server
has the following pattern:
<cfexchange***
action="get"
name="results query object name"
connection information>
<cfexchangefilter
name="filter type"
value"filter value>
<cfexchangefilter
name="data/time filter type"
from="start date/time"
to="end date/time">
.
.
.
</cfexchange>
If you specify multiple cfexchangefilter tags with differentname attributes, ColdFusion gets all items that
match all of the specified conditions.
If you specify multiple cfexchangefilter tags with identicalname attributes ColdFusion gets the items that
match only the last tag with the duplicate name attribute.
1217
The name attributes correspond to field names in the Exchange item records. The valid values for the name
attributes depend on the type of item you are getting. For detailed lists of the valid values, see the corresponding tag
references in the CFML Reference.
If the name attribute specifies a field that takes text or numeric information, you use the value attribute to specify
the condition.
If the name attribute specifies a field that takes a date, time, or date and time, you use the from and to attributes to
specify the range. You can omit one of these attributes to specify an open-ended range, such as all dates up to and
including December 1, 2007.
Date ranges are inclusive. The selected items include ones with the specified to or from dates.
You cannot use the empty string as a value attribute to search for an empty value. To find entries where a particular
field has an empty value, get all entries and use a query of queries to filter the results to include only entries where
the field is empty.
In fields that take text strings such as Message and or Subject, ColdFusion returns items that contain the exact
phrase that you specify in the value attribute.
When you use the cfexchangemail tag, ColdFusion gets only items a single folder. If you include a filter for a
folder, ColdFusion gets items that are directly in the Inbox only and does not search any subfolders. For an example
of getting information from multiple folders, see Getting and using folder names on page 1214.
When ColdFusion gets the results, it creates the query object specified in the name attribute, if it does not exist, and
populates each row with a single item such as a mail message. The query columns depend on the type of item. For
example, a mail message has FromID and ToID fields, and a contact has FirstName and LastName fields. For detailed
information on the returned structures, see the corresponding tag in the CFML Reference.
The query results for all types of items have two columns:
A UID column with the unique ID of the item. You use this value to specify the item when you delete, modify, or
(for calendar entries) respond to it. You also use the UID value to get the item attachments.
A HasAttachments column with a Boolean value specifying whether the item has any attachments. If this field is
true, you can use the getAttachments action to get the attachments.
The following example gets the mail messages that were sent during the last week to the docuser1 user from any e-mail
address that includes adobe.com. To keep this code short, the example uses the cfdump tag to show the results.
<cfset rightNow = Now()>
<cfset lastWeek = DateAdd("d","-7", rightNow)>
<cfexchangemail action="get" name="weeksMail"
username ="#user1#" password="#password1#"
server="#exchangeServerIP#">
<cfexchangefilter name="FromID" value="adobe.com">
<cfexchangefilter name="TimeSent" from="#lastWeek#" to="#rightNow#">
</cfexchangemail>
<cfdump var="#weeksMail#">
1218
The name of the query to hold the information about the returned attachments. When the tag completes
processing, the query object contains one record for each retrieved attachment. The query has six columns that
contain the filename, complete path to the saved attachment file, MIME type, file size, CID value (or an empty
string) and an indicator that shows whether the attachment is a message.
The path where the attachment is saved. (If you omit the path, ColdFusion does not get the attachments, but does
get the information about the attachments.)
Optionally, whether to create unique filenames by appending numbers to the names when two or more attachments
have the same names. (The default is to not create unique filenames.)
The following ColdFusion Exchange tag gets all attachments to the message identified by the theUID variable, saves
them in the C:/temp/cf_files/attachments directory, and stores information about the attachments in the attachInfo
structure:
<cfexchangemail action="getattachments"
connection="myconn1"
uid="#theUID#"
name="#attachInfo#"
attachmentPath="C:/temp/cf_files/attachments"
generateUniqueFilenames="true">
To get message attachments, you must have the UID of the message and know that the message has attachments. Use
a ColdFusion Exchange tag, such as cfexchangemail, with the get action to determine this information. When the
tag completes processing, the query specified by the name attribute includes the following columns:
1219
1220
2 Use cfexchangemail tag getattachments action to get the message attachments. Specify the UID of the mail
message you got in the previous step. Also specify an attachmentPath attribute value that is under your web root,
so that you can access the saved files by using a URL.
3 Search through the HTMLMessage field text that you got in step 1 and find the image items. Get the CID (content
value.
6 Display the resulting HTML.
The following example shows how to display a message with an inline image by retrieving the image from the
attachments.
<!--- Open the connection to the Exchange server. --->
<cfexchangeconnection
action="open"
username = "#user1#"
password = "#password1#"
server = "#exchangeServerIP#"
connection = "testconn">
<!--- Get the mail message. --->
<cfexchangeMail action="get" connection ="testconn" name="getMail">
<cfexchangeFilter name="Subject" value="sample inline image">
</cfexchangeMail>
<cfdump var="#getMail#">
<!--- The following code assumes we found only one matching message. --->
<cfoutput query="getMail">
<cfset theUID = #getMail.UID#>
<cfset htmlmessage = getMail.htmlmessage>
</cfoutput>
<!--- Get the message attachments. --->
<CFExchangeMail action="getAttachments" UID ="#theUID#" connection="testconn"
name="attachments"
attachmentPath="C:\ColdFusion8\wwwroot\My_Stuff\cfexchange\Book\attachments"
generateuniquefilenames="no">
<!--- Extract the image names from the mail message --->
<!--- Initialize the index into the message used in finding --->
<cfset findstart = 1>
<!--- Use an index loop to find all image source entries in the message --->
<!--- This example supports up to 25 inline images --->
<cfloop index="i" from="1" to="25">
<!--- find a cid: entry --->
<cfset stringStart[i] = Find('"cid:', htmlmessage, findstart)>
<!--- Exit the loop if no match was found --->
<cfif (stringstart[i] EQ 0)>
<cfbreak>
</cfif>
1221
1222
1223
server="#exchangeServerIP#"
event="#sEvent#"
uid="#Form.eventID#">
<cfoutput>Event ID #Form.eventID# Updated.</cfoutput>
</cfif>
</cfif>
<!--- A self-submitting form for the event information --->
<cfform format="xml" preservedata="true" style="width:500" height="600">
<cfinput type="text" label="Subject" name="subject" style="width:435">
<br />
<cfinput type="checkbox" label="All Day Event" name="allDay">
<cfinput type="datefield" label="Date" name="date" validate="date"
style="width:100">
<cfinput type="text" label="Start Time" name="startTime" validate="time"
style="width:100">
<cfinput type="text" label="End Time" name="endTime" validate="time"
style="width:100"><br />
<cfinput type="text" label="Location" name="location"
style="width:435"><br />
<cfinput type="text" label="Required Attendees" name="requiredAttendees"
style="width:435"><br />
<cfinput type="text" label="Optional Attendees" name="optionalAttendees"
style="width:435"><br />
<cfinput type="text" label="Resources" name="resources"
style="width:435"><br />
<cfinput type="text" label="Reminder (minutes)" validate="integer"
name="reminder" style="width:200">
<cfselect name="importance" label="Importance" style="width:100">
<option value="normal">Normal</option>
<option value="high">High</option>
<option value="low">Low</option>
</cfselect>
<cfselect name="sensitivity" label="Sensitivity" style="width:100">
<option value="normal">Normal</option>
<option value="company-confidential">Confidential</option>
<option value="personal">Personal</option>
<option value="private">Private</option>
</cfselect>
<cfinput type="textarea" label="Message" name="message" style="width:435;
height:100">
<cfinput type="hidden" name="eventID" value="#Form.EventID#">
<cfinput type="Submit" name="submit" value="Submit" >
</cfform>
1224
1225
<cfexchangeconnection
action="open"
username ="#user#"
password="#password#"
server="#exchangeServerIP#"
connection="conn1">
<!--- Get all meeting notifications from the Inbox. --->
<cfexchangemail action="get" name="requests" connection="conn1">
<cfexchangefilter name="MessageType" value="Meeting">
</cfexchangemail>
<!--- Get the meeting request data and put it in an array. --->
<cfset i=1>
<cfset meetingData=ArrayNew(1)>
<cfloop query="requests">
<cfexchangemail action="getmeetinginfo" connection="conn1"
name="meeting" meetinguid="#MeetingUID#" mailUID="#UID#">
<cfset meetingData[i]=meeting>
<cfset i=i+1>
</cfloop>
<!--- Loop through the request data array and delete any outdated
meeting messages from the Inbox. --->
<cfloop index="i" from="1" to="#ArrayLen(meetingData)#" >
<cfif meetingData[i].StartTime LTE now()>
<cfexchangemail action="delete" connection="conn1"
UID="#meetingData[i].UID#">
</cfif>
</cfloop>
<cfexchangeconnection
action="close"
connection="conn1">
For another example that deletes all mail from a known spam address, see Using persistent connections on
page 1210.
How to get detailed information about meeting requests, cancellation notices, and responses to invitations
How to specify event recurrence
1226
The information provided by the cfexchangemail tag with the get action does not provide detailed information
about meeting. It only includes the following meeting-related information:
attributes:
(Optional) A mailuid attribute with the UID of the message that contained the meeting notification. Use this
attribute to identify a specific message if the Inbox contains multiple messages about a single meeting.
3 Use the information returned in step 2 in application-specific logic to determine the required messages and actions.
For example, you could display all meeting requests in a form that lets a user submit a response to each message.
4 To respond to a meeting request, use the cfexchangecalendar tag with an action value of respond and set the
Set the uid attribute to the Meeting UID you received in step 2. Do not use the Message UID.
Specify a responseType value of accept, decline, or tentative.
(Optional) Specify a notify value of true (the default value) or false to control whether the event owner
receives a meeting response message.
If the owner receives a notification, you can also specify a message attribute with a text message that is included
in the response.
The following example shows how you can use this process. It displays all meeting invitations in the Inbox and lets the
user respond to each request and send a message with the response:
1227
<cfexchangeconnection
action="open"
username ="#user2#"
password="#password2#"
server="#exchangeServerIP#"
connection="conn1">
<cfif isDefined("Form.Submit")>
<!--- When the form has been submitted, send the responses. --->
<cfloop index="k" from="1" to="#Form.responses#">
<cfset resp = Form["response" & k] >
<cfset msg = Form["respMessage" & k] >
<cfset msguid = Form["UID" & k] >
<cfexchangecalendar action="respond" connection="conn1"
uid="#msguid#" responseType="#resp#" message="#msg#">
<cfoutput><h4>Response #k# sent!</h4></cfoutput>
</cfloop>
<cfelse>
<!--- Get all messages with meeting Requests. --->
<cfexchangemail action="get" name="requests" connection="conn1">
<cfexchangefilter name="MessageType" value="Meeting_Request">
</cfexchangemail>
<!--- Get the meeting request data. --->
<cfloop query="requests">
<cfexchangemail action="getmeetinginfo" connection="conn1"
name="meeting" meetinguid="#MeetingUID#">
<cfset meetingData[requests.currentrow]=meeting>
</cfloop>
<!--- Display the invitation data in a form. --->
<cfform name="bar">
<cfloop index="j" from="1" to="#ArrayLen(meetingData)#">
<cfoutput>
<h3>Meeting Request #j#</h3>
Subject: #meetingData[j].Subject# <br />
Sensitivity: #meetingData[j].Sensitivity# <br />
Organizer: #meetingData[j].Organizer# <br />
All Day?: #meetingData[j].AllDayEvent# <br />
Day: #DateFormat(meetingData[j].StartTime)#
Starts: #TimeFormat(meetingData[j].StartTime)#
Ends: #TimeFormat(meetingData[j].EndTime)# <br />
Duration: #meetingData[j].Duration# <br />
Location: #meetingData[j].Location# <br />
Message: #meetingData[j].Message# <br />
</cfoutput>
<!--- Specify the response to this invitation. --->
<h4>response:</h4>
<cfinput type="radio" checked name="response#j#" value="accept">
1228
Accept
<cfinput type="radio" name="response#j#" value="decline">Decline
<cfinput type="radio" name="response#j#" value="tentative">Tentative
<br />
<cftextarea name="respMessage#j#" label="Message (optional)"
width="300" height="200" />
<cfinput type="hidden" name="UID#j#"
value="#meetingData[j].MeetingUID#">
<hr />
</cfloop>
<cfinput type="hidden" name="responses"
value="#ArrayLen(meetingData)#">
<cfinput type="Submit" name="submit" value="Submit">
</cfform>
</cfif>
<cfexchangeconnection
action="close"
connection="conn1">
For an example that gets information about all declined meeting messages in the Inbox and all its subfolders, see the
example in Getting and using folder names on page 1214.
Note: If you omit all three of these fields, the event is created with no end date, and if you specify a count or end date,
the RecurrenceNoEndDate value is automatically false; therefore, Specify a RecurrenceNoEndDate field only if you
are changing an existing event with a recurrence count or end date to one with no end date.
Specify the recurrence details in additional fields that depend on the recurrence type.
To change an event recurrence, including to change whether the event recurs, you specify only the fields whose values
change. To stop an event from recurring, set the IsRecurring field to false. To convert an event from nonrecurring
to recurring, set the IsRecurring field to true and set all the necessary recurrence fields.
The following sections describe how to specify each type of recurrence. For detailed descriptions of the fields that you
use, see cfexchangecalendar in the CFML Reference.
Note: If you specify a recurrence rule that conflicts with the start date that you specify, the first occurrence of the event is
on first day following the start date that conforms to the rule, not on the start date. For example, if you schedule an event
for the second Tuesday of the month, and specify a start date of June 2, 2007, the first occurrence of the event is on June
12, 2007.
Specifying daily recurrence
To set a recurrence that is based on days, you do one of the following:
Define a RecurrenceFrequency field to specify the frequency of the event, in days. To schedule a meeting for every
third day, for example, specify RecurrenceFrequency="3".
1229
Define a RecurrenceFrequency field to specify the frequency of the event, in weeks. If you omit this field, the event
occurs every week. To schedule a meeting for every fourth week, for example, specify RecurrenceFrequency="4".
Specify a
RecurrenceDays field with a comma-delimited list of one of more of the following strings: MON, TUE, WED,
THUR, FRI, SAT, SUN. If you omit this attribute, the event recurs on the day of the week determined by the startTime
field value.
The following CFScript code sample sets an event that occurs on Tuesday and Thursday of every other week until
December 3, 2007.
IsRecurring="true";
RecurrenceType="WEEKLY";
RecurrenceEndDate="12/13/2007";
RecurrenceFrequency="2";
RecurrenceDays="TUE,THU;
Events that occur on the same date of each scheduled month, for example, on the tenth day of every three months.
Events that occur on the same week of the month and the same day of the week, for example, on the second thursday
of every month, or on the last Friday of every six months.
To specify a date-based monthly event, you only specify the recurrence type, and, if the recurrence is not every month,
the frequency. ColdFusion schedules the event to occur on the day of the week determined by the startTime field
value. To schedule a meeting that occurs on the start date every four months, specify the following recurrence fields:
IsRecurring="true";
RecurrenceType="MONTHLY";
RecurrenceFrequency="4";
To specify an event that occurs on the same day of the week, specify the following fields in addition to
RecurrenceType:
1230
Field
Description
RecurrenceFrequency
The frequency of the event, in months. If you omit this field, the event occurs every month.
RecurrenceWeek
The week of the month on which the event occurs. Valid values are first, second, third, fourth,
and last.
RecurrenceDay
The day of the week on which the event occurs. Valid values are SUN, MON, TUE, WED, THU, FRI, and SAT.
The following CFScript code sample sets an event that occurs on the third Thursday of every three months:
IsRecurring="true";
RecurrenceType="Monthly";
RecurrenceFrequency="3";
RecurrenceWeek="third";
RecurrenceDay="THU";
Events that occur on the same date of each year, for example, on every August 10.
Events that occur on a specific day week and month, for example, on the second Thursday of August.
To specify a date-based yearly event, you only specify the recurrence type. ColdFusion schedules the event to occur
each year on the date determined by the startTime field value. To schedule a meeting that occurs on the start date
every year, specify the following recurrence fields:
IsRecurring="true";
RecurrenceType="YEARLY";
To specify an event that occurs on the same day of the week and month each year, specify the following fields in
addition to RecurrenceType:
Field
Description
RecurrenceMonth
The month of the year which the event occurs. Valid values are JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG,
SEP, OCT, NOV, and DEC.
RecurrenceWeek
The week of the month during which the event occurs. Valid values are first, second, third,
fourth, and last.
RecurrenceDay
The day of the week on which the event occurs. Valid values are SUN, MON, TUE, WED, THU, FRI, and SAT.
The following CFScript code sample sets an event that occurs on the third Thursday of August three months:
IsRecurring="true";
RecurrenceType="YEARLY";
RecurrenceMonth="AUG";
RecurrenceWeek="third";
RecurrenceDay="THU";
1231
1232
sEvent.message=Form.Message;
</cfscript>
<cfdump var="#sEvent#">
<!--- Create the event in Exchange. --->
<cfexchangecalendar action="create"
username ="#user1#"
password="#password1#"
server="#exchangeServerIP#"
event="#sEvent#"
result="theUID">
<!--- Output the UID of the new event --->
<cfif isDefined("theUID")>
<cfoutput>Event Added. UID is#theUID#</cfoutput>
<cfset Form.eventID = theUID >
</cfif>
</cfif>
<cfform format="xml" preservedata="true" style="width:500" height="700">
<cfinput type="text" label="Subject" name="subject" style="width:435">
<br />
<cfinput type="checkbox" label="All Day Event" name="allDay">
<cfinput type="datefield" label="Date" name="date" validate="date"
style="width:100">
<cfinput type="text" label="Start Time" name="startTime" validate="time"
style="width:100">
<cfinput type="text" label="End Time" name="endTime" validate="time"
style="width:100"><br />
<cfinput type="text" label="Location" name="location"
style="width:435"><br />
<cfinput type="text" label="Required Attendees" name="requiredAttendees"
style="width:435"><br />
<cfinput type="text" label="Optional Attendees" name="optionalAttendees"
style="width:435"><br />
<cfinput type="text" label="Resources" name="resources"
style="width:435"><br />
<cfinput type="text" label="Reminder (minutes)" validate="integer"
name="reminder" style="width:200">
<cfselect name="importance" label="Importance" style="width:100">
<option value="normal">Normal</option>
<option value="high">High</option>
<option value="low">Low</option>
</cfselect>
<cfselect name="sensitivity" label="Sensitivity" style="width:100">
<option value="normal">Normal</option>
<option value="company-confidential">Confidential</option>
<option value="personal">Personal</option>
<option value="private">Private</option>
</cfselect>
<hr />
<!--- Recurrence Information --->
<cfinput type="checkbox" label="IsRecurring" name="isRecurring">
<cfinput type="checkbox" label="RecurrenceNoEndDate" name="noEndDate">
<cfinput type="text" label="RecurrenceCount" validate="integer"
required="false" name="recurrenceCount">
<cfinput type="text" label="RecurrenceEndDate" validate="date"
1233
required="false" name="recurrenceEndDate">
<cfselect name="RecurrenceType" label="Recurrence Type"
style="width:100">
<option value="DAILY">Daily</option>
<option value="WEEKLY">Weekly</option>
<option value="MONTHLY">Monthly</option>
<option value="YEARLY">Yearly</option>
</cfselect>
<cfinput type="text" label="RecurrenceFrequency" validate="integer"
name="recurrenceFrequency">
<cfinput type="checkbox" label="RecurEveryWeekDay"
name="recurEveryWeekDay">
<cfinput type="text" label="RecurrenceDays" name="recurrenceDays">
<cfinput type="text" label="RecurrenceDay" name="recurrenceDay">
<cfselect name="RecurrenceWeek" label="RecurrenceWeek" style="width:100">
<option value=""></option>
<option value="first">First</option>
<option value="second">Second</option>
<option value="third">Third</option>
<option value="fourth">Fourth</option>
<option value="last">Last</option>
<cfinput type="text" label="RecurrenceMonth" name="recurrenceMonth">
</cfselect>
<hr />
<cfinput type="textarea" label="Message" name="message" style="width:300;
height:100">
<cfinput type="Submit" name="submit" value="Submit" >
</cfform>
1234
Using the Get method, you can only send information to the remote server in the URL. This method is often used
for a one-way transaction in which cfhttp retrieves an object.
Using the Post method, you can pass variables to a ColdFusion page or CGI program, which processes them and
returns data to the calling page. The calling page then appears or further processes the data that was received. For
example, when you use cfhttp to Post to another ColdFusion page, that page does not appear. It processes the
request and returns the results to the original ColdFusion page, which then uses the information as appropriate.
2 (Optional) Replace the value of the url attribute with another URL.
3 Save the file as get_webpage.cfm in the myapps directory under your web_root and view it in the web browser.
The browser loads the web page specified in the url attribute.
Reviewing the code
The following table describes the code and its function:
Code
Description
<cfhttp method="Get"
url="http://www.adobe.com"
resolveurl="Yes">
Get the page specified in the URL and make the links absolute instead of relative
so that they appear properly.
<cfoutput>
#cfhttp.FileContent# <br>
</cfoutput>
1235
<html>
<head>
<title>Use Get Method</title>
</head>
<body>
<cfhttp
method = "Get"
url="http://www.adobe.com/software"
path="c:\temp"
file="adobe_software.htm">
</body>
</html>
2 (Optional) Replace the value of the url attribute with another URL and change the filename.
3 (Optional) Change the path from C:\temp to a path on your hard drive.
4 Save the page as save_webpage.cfm in the myapps directory under your web_root directory.
5 Go to the specified path and view the file that you specified in a text editor (using the values specified in step 1, the
path is C:\temp\macr_software.htm).
The saved file does not appear properly in your browser because the Get operation saves only the specified web page
HTML. It does not save the frame, image, or other files that the page could include.
Reviewing the code
The following table describes the code and its function:
Code
Description
<cfhttp
method = "Get"
url="http://www.adobe.com/software"
path="c:\temp"
file="macr_software.htm">
Get the page specified in the URL and save it in the file specified by the path and
file attributes.
When you use the path and file attributes, ColdFusion ignores any
resolveurl attribute. As a result, frames and other included files cannot appear
when you view the saved page.
2 (Optional) Replace the value of the url attribute with the URL of a binary file that you want to download.
3 (Optional) Change the path from C:\temp to a path on your hard drive.
4 Save the file as save_binary.cfm in the myapps directory under your web_root and open it in the web browser to
1236
Description
<cfhttp method="Get"
url="http://www.adobe.com/adobe/accessibility/
images/spotlight.jpg" path="c:\temp"
file="My_SavedBinary.jpg">
Get a binary file and save it in the path and file specified.
<cfoutput>
#cfhttp.MimeType#
</cfoutput>
You can specify a field delimiter with the delimiter attribute. The default is a comma.
If data in a field could include the delimiter character, surround the entire field with the text qualifier character,
which you can specify with the textqualifier attribute. The default text qualifier is the double-quotation mark (").
If a text qualifier exists, surround all field values with the text qualifier character.
To include the text qualifier character in a field, use a double character. For example, if the text qualifier is ", use ""
to include a quotation mark in the field.
The first row of text is always interpreted as column headings, so that row is skipped. You can override the file
column heading names by specifying a different set of names in the columns attribute. Specify a name for each
column. You then use these new names in your CFML code. However, ColdFusion never treats the first row of the
file as data.
When duplicate column heading names are encountered, ColdFusion adds an underscore character to the
duplicate column name to make it unique. For example, if two CustomerID columns are found, the second is
renamed "CustomerID_".
2 Save the file as text.txt in the myapps directory under your web_root.
3 Create a ColdFusion page with the following content:
1237
<cfhttp method="Get"
url="http://127.0.0.1/myapps/text.txt"
name="juneorders"
textqualifier="">
<cfoutput query="juneorders">
OrderID: #OrderID#<br>
Order Number: #OrderNum#<br>
Order Date: #OrderDate#<br>
</cfoutput>
<!--- Now substitute different column names --->
<!--- by using the columns attribute --->
<hr>
Now using replacement column names<br>
<cfhttp method="Get"
url="http://127.0.0.1/myapps/text.txt"
name="juneorders"
columns="ID,Number,ODate,SDate,Name,Address"
textqualifier="">
<cfoutput query="juneorders">
Order ID: #ID#<br>
Order Number: #Number#<br>
Order Date: #SDate#<br>
</cfoutput>
4 Save the file as query_textfile.cfm in the myapps directory under your web_root and view it in the web browser.
1238
<html>
<head>
<title>HTTP Post Test</title>
</head>
<body>
<h1>HTTP Post Test</h1>
<cfhttp method="Post"
url="http://127.0.0.1:8500/myapps/post_test_server.cfm">
<cfhttpparam type="Cookie"
value="cookiemonster"
name="mycookie6">
<cfhttpparam type="CGI"
value="cgivar "
name="mycgi">
<cfhttpparam type="URL"
value="theurl"
name="myurl">
<cfhttpparam type="Formfield"
value="[email protected]"
name="emailaddress">
<cfhttpparam type="File"
name="myfile"
file="c:\pix\trees.gif">
</cfhttp>
<cfoutput>
File Content:<br>
#cfhttp.filecontent#<br>
Mime Type:#cfhttp.MimeType#<br>
</cfoutput>
</body>
</html>
2 Replace the path to the GIF file to a path on your server (just before the closing cfhttp tag).
3 Save the file as post_test.cfm in the myapps directory under your web_root.
Description
<cfhttp method="Post"
url="http://127.0.0.1:8500/myapps/post_test_server
.cfm">
<cfhttpparam type="Formfield"
value="[email protected]" name="emailaddress">
1239
Code
Description
<cfoutput>
File Content:<br>
#cfhttp.filecontent#<br>
Display the contents of the file that the page that is posted to creates
by processing the request. In this example, the contents is the output
from the cfoutput tag in server.cfm.
Description
<cffile destination="C:\temp\"
nameconflict="Overwrite" filefield="Form.myfile"
action="Upload" attributes="Normal">
Write the transferred document to a file on the server. You send the
file using the type="File" attribute, but the receiving page gets it as
a Form variable, not a File variable. This cffile tag creates File variables,
as follows.
<cfoutput>
Output information. This page does not display the results. They are
passed back to the posting page in its cfhttp.filecontent
variable.
Output the value of the URL variable sent in the HTTP request.
Output the value of the Cookie variable sent in the HTTP request.
1240
Code
Description
Output the value of the CGI variable sent in the HTTP request.
Output the Form variable sent in the HTTP request. You send the
variable using the type="formField" attribute but the receiving
page gets it as a Form variable.
Output the results of the cffile tag on this page. This time, the
variables really are File variables.
1241
<html>
<head>
<title>FTP Test</title>
</head>
<body>
<h1>FTP Test</h1>
<!--- Open ftp connection --->
<cfftp connection="Myftp"
server="MyServer"
username="MyUserName"
password="MyPassword"
action="Open"
stoponerror="Yes">
<!--- Get the current directory name. --->
<cfftp connection=Myftp
action="GetCurrentDir"
stoponerror="Yes">
<!--- output directory name --->
<cfoutput>
The current directory is:#cfftp.returnvalue#<p>
</cfoutput>
<!--- Get a listing of the directory. --->
<cfftp connection=Myftp
action="listdir"
directory="#cfftp.returnvalue#"
name="dirlist"
stoponerror="Yes">
<!--- Close the connection.--->
<cfftp action="close" connection="Myftp">
<p>Did the connection close successfully?
<cfoutput>#cfftp.succeeded#</cfoutput></p>
<!--- output dirlist results --->
<hr>
<p>FTP Directory Listing:</p>
<cftable query="dirlist" colheaders="yes" htmltable>
<cfcol header="<B>Name</b>" TEXT="#name#">
<cfcol header="<B>Path</b>" TEXT="#path#">
<cfcol header="<B>URL</b>" TEXT="#url#">
<cfcol header="<B>Length</b>" TEXT="#length#">
<cfcol header="<B>LastModified</b>"
TEXT="#DateFormat(lastmodified)#">
<cfcol header="<B>IsDirectory</b>"
TEXT="#isdirectory#">
</cftable>
2 Change MyServer to the name of a server for which you have FTP permission.
3 Change MyUserName and MyPassword to a valid user name and password.
To establish an anonymous connection, enter anonymous as the user name and an e-mail address (by
convention) for the password.
1242
4 Save the file as ftp_connect.cfm in the myapps directory under your web_root and view it in the web browser.
Description
Use the Myftp connection to get the name of the current directory;
stop processing if an error occurs.
Use the Myftp connection to get a directory listing. Use the value
returned by the last cfftp call (the current directory of the
connection) to specify the directory to list. Save the results in a
variable named dirlist (a query object). Stop processing if an error
occurs.
Close the connection, and do not stop processing if the operation fails
(because you can still use the results). Instead, display the value of the
cfftp.succeeded variable, which is Yes if the connection is closed,
and No if the operation failed.
After you establish a connection with cfftp, you can reuse the connection to perform additional FTP operations until
either you or the server closes the connection. When you access an already-active FTP connection, you need not
respecify the user name, password, or server. In this case, make sure that when you use frames, only one frame uses
the connection object.
Note: For a single simple FTP operation, such as GetFile or PutFile, you need not establish a connection. Specify all the
necessary login information, including the server and any login and password, in the single cfftp request.
1243
In this example, the connection cache remains available to other pages within the current session. For this approach
to work, enable session variables in your application, and lock code that uses session variables. For more information
on locking, see Using Persistent Data and Locking on page 301.
Note: Changing connection characteristics, such the retrycount or timeout values, could require you to re-establish
the connection.
Attributes
Action
Attributes
Open
none
Rename
existing
new
Close
none
Remove
server
item
ChangeDir
directory
GetCurrentDir
none
CreateDir
directory
GetCurrentURL
none
ListDir
name
ExistsDir
directory
directory
RemoveDir
directory
ExistsFile
remotefile
GetFile
localfile
Exists
item
remotefile
PutFile
localfile
remotefile
1244
Using cffile
You can use the cffile tag to work with files on the server in several ways:
Upload files from a client to the web server using an HTML form
Move, rename, copy, or delete files on the server
Read, write, or append to text files on the server
You use the action attribute to specify any of the following file actions: upload, move, rename, copy, delete, read,
readBinary, write, and append. The required attributes depend on the action specified. For example, if
action="write", ColdFusion expects the attributes associated with writing a text file.
Note: Consider the security and logical structure of directories on the server before allowing users access to them. You can
disable the cffile tag in the ColdFusion Administrator. Also, to access files that are not located on the local ColdFusion
system, ColdFusion services must run using an account with permission to access the remote files and directories.
Uploading files
File uploading requires that you create two files:
2 Save the file as uploadfileform.cfm in the myapps directory under your web_root and view it in the browser.
Note: The form does not work until you write an action page for it (see the next procedure).
1245
Description
<form action="uploadfileaction.cfm"
enctype="multipart/form-data"
method="post">
Create a form that contains file selection fields for upload by the user. The action
attribute value specifies the ColdFusion template that processes the submitted
form. The enctype attribute value tells the server that the form submission
contains an uploaded file. The method attribute is set to post to submit a
ColdFusion form.
Allow the user to specify the file to upload. The file type instructs the browser to
prepare to read and transmit a file from the user system to your server. It
automatically includes a Browse button to let the user look for the file instead of
manually entering the entire path and filename.
The user can enter a file path or browse the system and select a file to send.
1 Create a ColdFusion page with the following content:
<html>
<head> <title>Upload File</title> </head>
<body>
<h2>Upload File</h2>
<cffile action="upload"
destination="c:\temp\"
nameConflict="overwrite"
fileField="Form.FiletoUpload">
<cfoutput>
You uploaded #cffile.ClientFileName#.#cffile.ClientFileExt#
successfully to #cffile.ServerDirectory#.
</cfoutput>
</body>
</html>
Description
<cffile action="upload"
Output the name and location of the uploaded file on the client machine.
destination="c:\temp\"
1246
Code
Description
nameConflict="overwrite"
fileField="Form.FiletoUpload">
Specify the name of the file to upload. Do not enclose the variable in number signs.
You uploaded
#cffile.ClientFileName#.#cffile.
ClientFileExt# successfully to
#cffile.ServerDirectory#.
Inform the user of the file that was uploaded and its destination. For information
on scope variables, see Evaluating the results of a file upload on page 1247.
Note: This example performs no error checking and does not incorporate any security measures. Before deploying an
application that performs file uploads, ensure that you incorporate both error handling and security. For more
information, see Securing Applications on page 339 and Handling Errors on page 275.
Resolving conflicting filenames
When you save a file to the server, a file with the same name could exist. To resolve this problem, assign one of these
values to the nameConflict attribute of the cffile tag:
Error (default) ColdFusion stops processing the page and returns an error. The file is not saved.
Skip Allows custom behavior based on file properties. The tag does not save the file or return an error.
Overwrite Overwrites a file that has the same name as the uploaded file.
MakeUnique Generates a unique filename for the uploaded file. The name is stored in the file object variables
serverFile and serverFileName. You can use this variable to record the name used when the file was saved. The unique
name might not resemble the attempted name. For more information on file upload status variables, see Evaluating
the results of a file upload on page 1247.
Controlling the type of file uploaded
For some applications, you could want to restrict the type of file that is uploaded, for example, to not accept graphic
files in a document library.
You use the accept attribute to restrict the type of file that you allow in an upload. When an accept qualifier is
present, the uploaded file MIME content type must match the criteria specified or an error occurs. The accept
attribute takes a comma-separated list of MIME data names, optionally with wildcards.
The browser determines the file MIME type. Common types, such as image/gif and text/plain, are registered in the
browser.
Note: Current versions of Microsoft Internet Explorer and Netscape support MIME type associations. Other browsers and
earlier versions might ignore these associations.
ColdFusion saves any uploaded file if you omit the accept attribute or specify "*/*". You can restrict the file types, as
demonstrated in the following examples.
The following cffile tag saves an image file only if it is in the GIF format:
<cffile action="Upload"
fileField="Form.FiletoUpload"
destination="c:\uploads\"
nameConflict="Overwrite"
accept="image/gif">
The following cffile tag saves an image file only if it is in GIF or JPEG format:
1247
<cffile action="Upload"
fileField="Form.FiletoUpload"
destination="c:\uploads\"
nameConflict="Overwrite"
accept="image/gif, image/jpeg">
Note: If you receive an error like "The MIME type of the uploaded file (image/jpeg) was not accepted by the server", enter
accept="image/jpeg" to accept JPEG files.
This cffile tag saves any image file, regardless of the format:
<cffile action="Upload"
fileField="Form.FiletoUpload"
destination="c:\uploads\"
nameConflict="Overwrite"
accept="image/*">
Hidden
Normal
ReadOnly
To specify several attributes in CFML, use a comma-separated list for the attributes attribute; for example,
attributes="ReadOnly,Hidden". If you do not use the attributes attribute, the existing attributes of the file are
maintained. If you specify any other attributes in addition to Normal, the additional attribute overrides the Normal
setting.
UNIX
In UNIX, you can individually set permissions on files and directories for each of three types of usersowner, group,
and other. You use a number for each user type. This number is the sum of the numbers for the individual permissions
allowed. Values for the mode attribute correspond to octal values for the UNIX chmod command:
4 = read
2 = write
1 = execute
You enter permissions values in the mode attribute for each type of user: owner, group, and other in that order. For
example, use the following code to assign read permissions for everyone:
mode=444
To give a file or directory owner read/write/execute permissions and read-only permissions for everyone else:
mode=744
1248
You can access file upload status variables using dot notation, using either file.varname or cffile.varname. Although
you can use either the File or cffile prefix for file upload status variables, cffile is preferred; for example,
cffile.ClientDirectory. The File prefix is retained for backward compatibility.
Note: File status variables are read only. They are set to the results of the most recent cffile operation. If two cffile tags
execute, the results of the first are overwritten by the subsequent cffile operation.
The following table describes the file upload status variables that are available after an upload:
Variable
Description
attemptedServerFile
Initial name that ColdFusion uses when attempting to save a file; for example, myfile.txt. (see
Resolving conflicting filenames on page 1246).
clientDirectory
Directory on the client system from which the file was uploaded.
clientFile
Full name of the source file on the client system with the filename extension; for example,
myfile.txt.
clientFileExt
Extension of the source file on the client system without a period; for example, txt (not .txt).
clientFileName
Name of the source file on the client system without an extension; for example, myfile.
contentType
MIME content type of the saved file; for example, image for image/gif.
contentSubType
MIME content subtype of the saved file; for example, gif for image/gif.
dateLastAccessed
fileExisted
Indicates (Yes or No) whether the file existed with the same path.
fileSize
fileWasAppended
Indicates (Yes or No) whether ColdFusion appended the uploaded file to an existing file.
fileWasOverwritten
fileWasRenamed
Indicates (Yes or No) whether the uploaded file was renamed to avoid a name conflict.
fileWasSaved
oldFileSize
Size of the file that was overwritten in the file upload operation. Empty if no file was overwritten.
serverDirectory
serverFile
Full name of the file saved on the server with the filename extension; for example, myfile.txt.
serverFileExt
Extension of the file saved on the server without a period; for example, txt (not .txt).
serverFileName
Name of the file saved on the server without an extension; for example, myfile.
timeCreated
timeLastModified
1249
Action
Example code
Move a file
Rename a file
Copy a file
Delete a file
This example sets the ReadOnly flag bit for the uploaded file:
<cffile action="Copy"
source="c:\files\upload\keymemo.doc"
destination="c:\files\backup\"
attributes="ReadOnly">
Note: Ensure that you include the trailing slash (\) when you specify the destination directory. Otherwise, ColdFusion
treats the last element in the path as a filename. This rule only applies to copy actions.
Create log files. (You can also use cflog to create and write to log files.)
Generate static HTML documents.
Use text files to store information that can be incorporated into web pages.
Reading a text file
You can use the cffile tag to read an existing text file. The file is read into a local variable that you can use anywhere
in the application page. For example, you could read a text file and then insert its contents into a database, or you could
read a text file and then use one of the string replacement functions to modify the contents.
2 Replace C:\inetpub\wwwroot\mine\message.txt with the location and name of a text file on the server.
1250
3 Save the file as readtext.cfm in the myapps directory under your web_root and view it in the browser.
2 Save the file as writetextfileform.cfm in the myapps directory under your web_root.
Note: The form does not work until you write an action page for it (see the next procedure).
The text file is written to the location you specified. If the file exists, it is replaced.
1251
3 Save the file as writetextfileaction.cfm in the myapps directory under your web_root.
4 View the file in the browser, enter values, and submit the form.
Using cfdirectory
Use the cfdirectory tag to return file information from a specified directory and to create, delete, and rename
directories. When listing directory contents or deleting a directory, you can optionally use the recurse attribute to
access or delete all subdirectories.
As with the cffile tag, you can disable cfdirectory processing in the ColdFusion Administrator. For details on the
syntax of this tag, see the CFML Reference.
Note: ColdFusion supports the ReadOnly and Hidden values for the attributes attribute for cfdirectory sorting.
Depending on whether your server is on a UNIX system or a Windows system, either the Attributes column or the
Mode column is empty. Also, you can specify a filename in the filter attribute to get information on a single file.
The following procedure describes how to create a ColdFusion page in which to view directory information.
1252
Using cfcontent
The cfcontent tag downloads files from the server to the client. You can use this tag to set the MIME type of the content
returned by a ColdFusion page and, optionally, define the name of a file for the current page to download. By default,
ColdFusion returns a MIME content type of text/html so that a web browser renders your template text as a web page.
As with the cffile and cfdirectory tags, you can disable processing in the ColdFusion Administrator.
1253
A MIME content type consists of "type/subtype" format. The following are common MIME content types:
text/html
image/gif
application/pdf
2 Save the file as cfcontent_message.htm in the myapps directory under your web_root.
The ColdFusion file that you write in steps 3 through 7 calls this file.
3 Create a ColdFusion page with the following content:
<html>
<head>
<title>cfcontent Example</title>
</head>
<body>
<h3>cfcontent Example</h3>
<cfcontent
type = "text/html"
file = "C:\CFusion\wwwroot\myapps\cfcontent_message.htm"
deleteFile = "No">
</body>
</html>
The text displays as unformatted text, in which HTML tags are treated as text.
The following example shows how the cfcontent tag can create an Excel spreadsheet that contains your data.
Create an Excel spreadsheet with cfcontent
1 Create a ColdFusion page with the following content:
1254
2 Save the file as employees_to_excel.cfm in the myapps directory under your web_root and view it in the browser.
1255
ColdFusion event gateways do not require HTTP requests. ColdFusion developers can write ColdFusion gateway
applications without using any CFM pages (just CFCs).
ColdFusion CFCs can use event gateways to listen for and respond directly to external events.
Event gateways operate asynchronously. A gateway typically gets a message and dispatches it for processing,
without requiring or waiting for a response.
ColdFusion developers can create event gateways to handle any type event that a Java application can receive.
ColdFusion includes several product-level event gateways, such as a gateway for the XMPP (Extensible Messaging and
Presence Protocol) instant messaging protocol. Adobe also provides the source for several example gateways, such as
a generalized socket gateway, that you can extend to handle your specific needs. You can also write your own gateways
in Java to handle other event or messaging technologies supported by the Java runtime or by third-party providers,
such as gateways for additional instant messaging protocols, gateways for specific ERP systems, or other protocols,
such as NNTP.
Mobile phones and other devices that support short messaging services (SMS)
XMPP or IBM Sametime Instant message clients
Java Sockets (which let your ColdFusion application communicate with TCP/IP-based devices and programs, such
as Telnet terminal clients).
Java Messaging Service (JMS) resources, such as storefront sales order handling systems.
Event gateways are not limited to sending or receiving information using communications protocols. For example,
ColdFusion includes an example event gateway that monitors changes to a directory and invokes a CFC method
whenever the directory changes. ColdFusion also includes an event gateway that lets a CFML application call a CFC
asynchronously and continue processing without getting a response from the CFC.
Just as you can create event gateways that serve many different event or messaging based technologies, you can write
many kinds of applications that use them. Just a few examples of possible gateway uses include the following.
Server to client push examples
An application that sends an instant message (IM) or SMS text message to a person who can approve a purchase
order, get a response, and mark the purchase order as approved or denied.
A bot that notifies users through their preferred messaging method (mobile phone, instant messaging, or even email) when watch list stock goes up, and offers to buy or sell the stock immediately.
An application that authenticates web users by sending them an SMS message that includes code that they must to
enter into the browser to proceed.
Client to server examples
A menu-based SMS application that lets users get information from any of several web service data providers.
ColdFusion includes an SMS menuing example int the gateways/cfc directory.
An instant messaging application that takes messages from users to technical support and assigns and directs the
messages to the most available support staff member. The application could also log the user ID and session, and
you could use ColdFusion to generate usage reports.
1256
A directory lookup robot IM "buddy" that responds to messages chat contain an employee name with the
employees phone number or buddy ID.
Server to serve examples
A JMS subsystem that publishes status updates that business intelligence systems consume.
document uses the term event gateway, without the word type or instance, for the general concept of a ColdFusion
event gateway. Where the context makes the meaning obvious, the term can also mean event gateway type or event
gateway instance.
Event gateway type A specific event gateway implementation, represented by a Java class. Each event gateway type
handles messages belonging to a particular a communications method or protocol, such as short message service
(SMS), an instant messaging protocol, or Sockets. You generally have one event gateway type per communication
protocol. You configure each event gateway type on the Gateway Types page in the Event Gateways area in the
ColdFusion Administrator.
Event gateway instance A specific instance of an event gateway type class. You configure each event gateway instance
on the ColdFusion Gateway Instances page by specifying the event gateway type, an ID, the path to the event gateway
application CFC that uses this instance, and a configuration file (if needed for the selected event gateway type). You
can have multiple event gateway instances per event gateway type, for example, for different event gateway
applications.
Event gateway application One or more CFCs and any supporting CFM pages that handle events from an event
gateway instance and send messages using the event gateway instance. The event gateway application is not part of an
event gateway instance, but the code that is responsible for processing event messages to and from the instance.
Event gateway listener Code in an event gateway that receives events from an event source and passes them to the
ColdFusion gateway service for delivery to a CFML listener CFC.
Listener CFC A CFC that contains one or more methods that respond to incoming messages from one or more event
1257
SMSC server
(for SMS
messages )
Instant
messaging
provider
.
.
.
.
Other message
generator /
receiver
Event
Event
Event
Event
Event
Event
Event Gateway
Instance
Event Gateway
Instance
CFEvent
CFEvent
Java
Listener
CFC
Event Gateway
Application
CFEvent
Message
CFEvent
.
.
.
.
Event Gateway
Instance
CFEvent
Message
CFEvent
ColdFusion
Event
Gateway
Service
CFEvent
Listener
CFC
Message
CFM
Page
CFEvent
CFEvent
ColdFusion
Listener
CFC
Event Gateway
Application
.
.
.
Event Gateway
Application
CFML
1258
Provide the ColdFusion application with access to a helper class that provides event gateway-specific services, such
as buddy-list management or connection management.
Use a file that specifies configuration information, such as IP addresses and ports, passwords, and other ID
information, internal time-out values, and so on.
as mobile phones or pagers. For detailed information on using the SMS event gateway, see Using the SMS Event
Gateway on page 1292.
XMPP (Extensible Messaging and Presence Protocol): An open, XML-based protocol for instant messaging. For
detailed information on using the XMPP event gateway, see Using the Instant Messaging Event Gateways on
page 1276.
1259
An SMS client (phone simulator) and a short message service center (SMSC) server simulator, for developing SMS
applications without requiring an external SMS provider.
A simple echo application that sends back the messages that it receives.
A temperature converter, an asynchronous logging application.
An application that returns employee phone number and other information.
The chapters in this document use these example applications.
JavaDoc documentation for the Java interfaces and classes that you use to create gateways.
For more information on these examples, see Using the example event gateways and gateway applications on
page 1271.
1260
Directory
Purpose
cfc
Event gateway application CFCs. ColdFusion is installed with an Administrator Mapping between /gateway and
this cfc directory.
cfc/examples
config
Configuration files for all ColdFusion event gateways, including standard ColdFusion event gateways, such as
SMS, and example event gateways, such as the directory watcher event gateway.
doc/api
JavaDoc for the Gateway, and GatewayHelper interfaces, and the CFEvent, GatewayServices, and GenericGateway
classes that gateway developer use when writing gateways. This documentation is a subset of the information in
Gateway development interfaces and classes in the CFML Reference.
lib
Executable code for example and user-developed event gateway classes. The ColdFusion class loader includes
this directory on its classpath and includes any JAR files that are in that directory on the class path. The
examples.jar file in this directory contains the class files for the DirectoryWatcherGateway, EmptyGateway, and
SocketGateway classes.
src/examples
Source code for the example event gateway classes that Adobe provides. Includes the EmptyGateway.java file
and the following subdirectories:
Settings
Gateway types
Gateway Instances
The Settings page lets you enable and disable support for event gateways, specify the number of threads that
ColdFusion can devote to processing events, specify the maximum number events that ColdFusion can hold in its
event queue (which holds events that are waiting to be processed) and start the SMS test server.
The Gateway Types page lets you add, remove, and configure event gateway types by specifying a name, a Java class,
and startup time-out behavior.
Note: The gateway type name in the ColdFusion Administrator does not have to be the same as the gateway type that is
used in the gateway Java code and the CFEvent data structure; however, use the same name in both places for consistency.
The Gateway Instances page lets you add, remove, configure, start, and stop individual event gateway instances. You
configure an event gateway instance by specifying a unique ID, the gateway type, one or more listener CFC paths, a
configuration file (not required for all gateway types), and a startup mode (manual, automatic, or disabled).
1261
One or more listener CFCs that handle any incoming messages and send any necessary responses.
In some applications, ColdFusion pages that generate outgoing messages directly.
An event gateway instance configuration in the ColdFusion Administrator. This configuration could require a
separate event gateway configuration file.
In some applications, a GatewayHelper object to provide access to additional features of the protocol or technology;
for example, to manage instant messaging buddy lists.
1262
An event gateway ID to identify the specific event gateway instance. You use this value in the CFML
GetGatewayHelper and SendGatewayMessage functions.
The event gateway type, which you select from the available event gateway types, such as SMS or Socket.
The absolute path to the listener CFC or CFCs that handles incoming messages. If you have multiple listener CFCs,
enter the paths separated by commas. Specify absolute file paths, even if you place the CFCs in the ColdFusion
gateway\cfc directory.
SendGatewayMessage CFML functions to send messages from outside the listener CFC (or, optionally, from the CFC)
GatewayHelper objects
The eventgateway log file
Unlike other ColdFusion applications, responder applications are request-free. They do not have CFM pages, just
CFCs, and they do not respond to HTTP requests. Instead, ColdFusion the event gateway service deliver the event
messages directly to the listener CFC, and the CFC listener method returns any response directly to the event gateway
service. Applications that allow mobile phone owners to get a news feed, check for text messages, or request other
forms of information follow this model.
Initiator applications are like most ColdFusion applications. At some point, ColdFusion executes a CFM page in
response to a request. (The ColdFusion Administrator Scheduled Tasks page can initiate the request.) ColdFusion
sends a message to the event gateway when the application calls a CFML SendGatewayMessage function. An
application that uses SMS to notify customers when orders have been shipped follows this model.
1263
1264
Other event gateways require different fields in the return structure. For example, to echo a message using the SMS
event gateway, you use the following lines to specify the return value:
<cfset
<cfset
<cfset
<cfset
retValue.command = "submit">
retValue.sourceAddress = arguments.CFEVENT.gatewayid>
retValue.destAddress = arguments.CFEVENT.originatorid>
retValue.ShortMessage = "Echo: " & arguments.CFEvent.Data.MESSAGE>
Description
GatewayID
The event gateway that sent the event; the value is the ID of an event gateway instance configured on the
ColdFusion Administrator Gateway Instances page. If the application calls the SendGatewayMessage function
to respond to the event gateway, it uses this ID as the functions first parameter.
Data
A structure containing the event data, including the message. The Data structure contents depend on the event
gateway type.
OriginatorID
The originator of the message. The value depends on the protocol or event gateway type. Many event gateways
require this value in response messages to identify the destination of the response. Identifies the sender of the
message.
GatewayType
The type of event gateway, such as SMS. An application that can process messages from multiple event gateway
types can use this field. This value is the gateway type name that the event Gateway class specifies. It is not
necessarily the same as the gateway type name in the ColdFusion Administrator.
CFCPath
The location of the listener CFC. The listener CFC does not require this field.
CFCMethod
The listener method that ColdFusion invokes to process the event. The listener CFC does not require this field.
CFCTimeout
The time-out, in seconds, for the listener CFC to process the event request. The listener CFC does not require this
field.
When a ColdFusion application responds to an event gateway message, or sends a message independently, it does not
use a CFEvent structure. However, the ColdFusion event gateway service creates a Java CFEvent instance with the
message data before calling the outgoingMessage method of the event gateway.
Using persistent scopes in listener CFCs
ColdFusion listener CFCs can use the Application, Client, and Session persistent scopes.
Because incoming event gateway messages are not associated with HTTP requests, ColdFusion uses different session
and client IDs for interactions initiated by these events than for CFM Page requests, as follows:
1265
Identifier
Structure
Session ID
gatewayType_gatewayID_originatorID
cfid
originatorID
cftoken
gatewayType_gatewayID
The gatewayID value is the event gateway ID that you set in the ColdFusion Administrator, and gatewayType and
originatorID are the values that the event gateway sets in the CFEvent instance for an incoming message.
Application scope
The Application scope lets the CFC share data with any ColdFusion page or CFC that uses the same application name.
This way, a listener CFC can use the same Application scope as CFML pages that send messages. Also, you can place
multiple listener CFCs in a single directory and have them share an Application.cfc or Application.cfm file and
application name.
As with all ColdFusion code, use the Application.cfc This.name variable or the cfapplication tag to set the
application name. The listener CFC can use an Application.cfc or Application.cfm file if the CFC is in a directory that
is in or under one of the following places:
1266
Place trace variables in the Application scope. These variables persist, and you can specify an application name for
your CFC (see Application scope on page 1265). You can inspect the Application scope contents, including your
trace variables, in any CFML page that has the same application name as your CFC.
Use cflog tags to help you trace any errors by logging significant events to a file. Also, carefully inspect the
eventgateway.log and exceptions.log files that ColdFusion maintains. For more information on using the
eventgateway.log file, see The eventgateway.log file on page 1260.
You can simulate responses from CFCs to the event gateway by using the SendGatewayMessage function in a CFM
page. The functions message parameter should contain the information that the CFC would place in its return
variable.
If you run ColdFusion from the command line, you can use the Java System.out.println method to write
messages to the console window, as the following code shows:
<cfscript>
sys = createObject("java", "java.lang.System");
sys.out.println("Debugging message goes here");
</cfscript>
Note: You do not have to restart the event gateway instance when you change a CFC. ColdFusion automatically uses the
updated CFC when the next event occurs.
Example event gateway CFC
The following code shows a temperature scale converter tool that can work with any of several event gateways: SMS,
XMPP, Lotus Sametime, or the example Socket event gateway. Users enter a string that consists of the temperature
scale (F, Fahrenheit, C, or Celsius), a comma, and a temperature on their device. The CFC converts Celsius to
Fahrenheit or Fahrenheit to Celsius, and returns the result.
This example shows how a responder event gateway application can work, and illustrates how different event gateway
types require different outgoing message formats:
<cfcomponent displayname="tempconverter" hint="Convert temperatures between
Celsius and Fahrenheit">
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<!--- Standard error message giving the correct input format. --->
<cfset var errormsg = "Please enter scale, integer where scale is F or C,
for example:F, 32">
<!--- Get the message. --->
<cfset data=cfevent.DATA>
<cfset message="#data.message#">
<!--- Where did it come from? --->
<cfset orig="#CFEvent.originatorID#">
<!--- Process the input, generate a message with the new temperature. --->
<!--- Input format is: degrees, temperature. --->
<cfif listlen(message) eq 2>
<cfif (listgetat(message,1) IS "F") OR
(listgetat(message,1) IS "Fahrenheit") OR
1267
(listgetat(message,1) IS "C") OR
(listgetat(message,1) IS "Celsius")>
<cfset scale=listgetat(message,1)>
<cfif isNumeric(listgetat(message,2))>
<cfset temperature=listgetat(message,2)>
<cfswitch expression="#scale#">
<cfcase value="F, Fahrenheit">
<cfset retmsg = temperature & " degrees Fahrenheit is "
& (temperature-32.0) * (5.0/9.0) & " degrees Celsius">
</cfcase>
<cfcase value="C, Celsius">
<cfset retmsg = temperature & " degrees Celsius is "
&(temperature * 9.0/5.0) + 32 & " degrees Fahrenheit">
</cfcase>
</cfswitch>
<cfelse>
<cfset retmsg=errormsg>
</cfif>
<cfelse>
<cfset retmsg=errormsg>
</cfif>
<cfelse>
<cfset retmsg=errormsg>
</cfif>
<!--- Fill the return value as required for the event gateway type. --->
<cfif arguments.CFEVENT.GatewayType is "Socket">
<cfset retValue = structNew()>
<cfset retValue.MESSAGE = retmsg>
<cfset retValue.originatorID = orig>
<cfelseif (arguments.CFEVENT.GatewayType is "Sametime") OR
(arguments.CFEVENT.GatewayType is "XMPP")>
<cfset retValue = structNew()>
<cfset retValue.MESSAGE = retmsg>
<cfset retValue.BuddyID = arguments.CFEVENT.DATA.SENDER>
<cfset retValue.originatorID = orig>
<cfelseif arguments.CFEVENT.GatewayType is "SMS">
<cfset retValue = structNew()>
<cfset retValue.command = "submit">
<cfset retValue.sourceAddress = arguments.CFEVENT.gatewayid>
<cfset retValue.destAddress = arguments.CFEVENT.originatorid>
<cfset retValue.shortMessage = retmsg>
</cfif>
<!--- Send the return message back. --->
<cfreturn retValue>
</cffunction>
</cfcomponent>
1268
SendGatewayMessage(gatewayID, messageStruct)
The gatewayID parameter must be the gateway ID specified in the ColdFusion Administrator for the event gateway
instance that sends the message.
The messageStruct parameter is a structure whose contents depends on the requirements of the outgoingMessage
method of the event gateway, and possibly the recipient application. For example, in addition to any message, the
structure could include a destination identifier.
The CFEvent instance passed to the event gateway contains these two parameters in the GatewayID and Data fields;
the remaining fields are empty.
The following example sends a message to a logging CFC, which logs information to a file. If the SendGatewayMessage
function returns OK, the example code displays a message. The code uses an instance of the asynchronous CFML
event gateway named Asynch Logger. The props variable used in the messageStruct parameter has two entries, the
destination file and the message to log.
<cfscript>
status = "No";
props = structNew();
props.Message = "Replace me with a variable with data to log";
status = SendGatewayMessage("Asynch Logger", props);
if (status IS "OK") WriteOutput("Event Message ""#props.Message#"" has been sent.");
</cfscript>
Note: To see the code for the CFC that logs the information, see Using the CFML event gateway for asynchronous CFCs
on page 1269.
1269
The standard ColdFusion event gateways log errors in interaction with any messaging server, errors in messages sent
by the ColdFusion application, and recoverable errors in event gateway operation. The event gateways also log
informational status messages for significant normal events, including event gateway initialization and restarts.
ColdFusion event gateway messages in the eventgateway.log file normally have the following format:
gatewayType (gatewayID) message body
When you are developing an event gateway application, you can use the ColdFusion Log viewer to inspect the
eventgateway.log file and filter the display by using the gateway type and possibly the gateway ID as keywords. By
selecting different severity levels, you can get a good understanding of errors and possible inefficiencies in your
application and event gateway operation.
the event gateway type (see Deploying an event gateway on page 1333).
2 If the event gateway type requires a configuration file, ensure that a valid file exists in the gateway\config directory.
Some event gateways could be designed to let multiple event gateway instances share a configuration file. Others
could require a separate file for each event gateway instance.
3 Install the event gateway application listener CFC and any other application components. ColdFusion provides a
cf_root\gateways\cfc directory as a convenient location for these CFCs, and includes a mapping in the ColdFusion
Administrator page for that directory. However, ColdFusion does not require you to install the listener CFC in this
directory.
4 Configure an event gateway instance on the Gateway Instances page of the Event Gateways section in the
Reindexing a Verity collection with new information without delaying an application, for example, when a user
uploads a new file
1270
The structure can include any number of fields with arbitrary contents for use in by the CFC.
Several optional fields can configure how the gateway delivers the information to the CFC.
The CFML gateway looks for the following optional fields, and, if they exist, uses them to determine how it delivers
the message. Do not use these field names for data that you send to your CFC method.
Field
Use
cfcpath
Overrides the CFC path specified in the ColdFusion Administrator. This field lets you use a single gateway
configuration in the ColdFusion Administrator multiple CFCs.
method
Sets the name of the method to invoke in the CFC. The default method is onIncomingMessage. This field lets
you use a single gateway configuration in the ColdFusion Administrator for a CFC that has several methods.
originatorID
Sets the originatorID field of the CFEvent object that ColdFusion delivers to the CFC. The default value is
CFMLGateway.
timeout
Sets the time-out, in seconds, during which the listener CFC must process the event request and return before
ColdFusion gateway services terminates the request. The default value is the Timeout Request value set on the
Server Settings page in the ColdFusion Administrator. Set this value if a request could validly take longer to
process than the default timeout; for example, if the request involves a long processing time.
instance ID that you specified in step 2. The SendGatewayMessage function returns true if the gateway successfully
queues the message in the ColdFusion Gateway Service; false, otherwise. It does not ensure that the CFC receives
or processes the message.
5 Run your CFML application.
1271
file The name of the file in which to place the message. The default value is defaultEventLog.
type The cflog type attribute to use. The default value is info.
message The message text.
<cfcomponent>
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cfscript>
if (NOT IsDefined("CFEvent.Data.file")) {
CFEvent.Data.file="defaultEventLog"; }
if (NOT IsDefined("CFEvent.Data.type")) {
CFEvent.Data.type="info"; }
</cfscript>
<cflog text="#CFEvent.Data.message#"
file="#CFEvent.Data.file#"
type="#CFEvent.Data.type#"
thread="yes"
date="yes"
time="yes"
application="yes">
</cffunction>
</cfcomponent>
1272
EmptyGateway
The EmptyGateway.java file contains an event gateway template that you can use as a skeleton for creating your own
event gateway. For more information on this class, and on creating new event gateways, see Creating Custom Event
Gateways on page 1320
SocketGateway
The SocketGateway event gateway listens on a TCP/IP port. Therefore, you can use this gateway for applications that
send and respond to messages using TCP/IP-based protocols such as Telnet, or for applications that send messages
between sockets. For example, a simple gateway application that responds to messages from a Telnet terminal client
without supporting the full Telnet protocol.
Note: The ColdFusion Administrator uses Socket as the gateway type name for the SocketGateway class.
The SocketGateway.java file defines two classes: SocketGateway, the event gateway, and SocketHelper, a
GatewayHelper class. The Source file is located in the gateway\src\examples\socket directory.
SocketGateway Listens on a TCP/IP port. This event gateway is multi-threaded and can handle multiple clients
simultaneously. It can send outgoing messages to existing clients, but cannot establish a link itself.
By default, the SocketGateway class listens on port 4445, but you can specify the port number in a configuration file.
The file should contain a single line in the following format:
port=portNumber
DirectoryWatcherGateway
The DirectoryWatcherGateway event gateway sends events to the listener CFC when a file is created, deleted, or
modified in a directory. The watcher runs in a thread that sleeps for an interval specified in the configuration file, and
when the interval has passed, checks for changes since the last time it was awake. If it finds added, deleted, or changed
files, it sends a message to a listener CFC. You can configure separate CFCs for add, delete, and change events, or use
a single CFC for all events. The source for this event gateway is located in the gateway/src/examples/watcher directory.
Note: The ColdFusion Administrator uses DirectoryWatcher as the gateway type name for the
DirectoryWatcherGateway class.
Configuration file
This event gateway requires a configuration file, consisting of lines in the following format:
directory=C:/temp
Note: If you use backward slash characters (\) as directory separators in Windows the file paths, escape them by using
double slashes, as in C:\\temp. You can use forward slashes (/) as the directory separator on all operating systems,
including Windows.
Note: When you specify filename extensions in the Directory Watcher configuration file, do not include the period,
instead use a comma, for example, doc,txt.
The configuration file can have comment lines, preceded by a number sign (#). If you omit a property or comment it
out, ColdFusion uses the default value. If you specify a property with no value, ColdFusion sets an empty property.
The configuration file can define the following values:
1273
Property
Req/Opt
Description
directory
Required
recurse
Optional
extensions
Optional
Comma-delimited list of extensions to watch. The event gateway logs only changed files with these
extensions. An asterisk (*) indicates all files. The default value is all files.
interval
Optional
Number of milliseconds between the times that the event gateway checks the directory. The
default value is 60 seconds.
addFunction
Optional
Name of the function to call when a file is added. The default value is onAdd.
changeFunction
Optional
Name of the function to call when a file is changed. The default value is onChange.
deleteFunction
Optional
Name of the function to call when a file is deleted. The default value is onDelete.
onAdd
onChange
onDelete
The CFEvent.Data field sent to the listener methods includes the following fields:
Field
Description
TYPE
FILENAME
Absolute path from the system directory root to the file that was added, deleted, or changed.
LASTMODIFIED
The date and time that the file was created or modified. This field is not included if the file was deleted.
The event gateway supports multiple listener CFCs and sends the event messages to all listeners. The event gateway is
one way; it watches for events and dispatches event information to a CFC, but it does not accept return values from
the CFC or input from SendGatewayMessage functions.
The directory watcher logs errors to the watcher.log file in the ColdFusion logs directory.
Example DirectoryWatcher application
The following code shows a simple directory watcher application. It enters a line in a log file each time a file is added,
deleted, or changed in the directory specified in the configuration file. ColdFusion includes the date and time that a
log entry is made. However, if the directory watcher monitors changes infrequently, for example once every minute or
more, the time in the log entry could differ from the time a file was added or changed, so the information includes the
time (but not date) for these actions.
1274
<cfcomponent>
<cffunction name="onAdd" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset data=CFEvent.data>
<cflog file="MydirWatcher" application="No"
text="ACTION: #data.type#;FILE: #data.filename#;
TIME: #timeFormat(data.lastmodified)#">
</cffunction>
<cffunction name="onDelete" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset data=CFEvent.data>
<cflog file="MydirWatcher" application="No"
text=" ACTION: #data.type#;FILE: #data.filename#">
</cffunction>
<cffunction name="onChange" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset data=CFEvent.data>
<cflog file="MydirWatcher" application="No"
text=" ACTION: #data.type#;FILE: #data.filename#;
TIME: #timeFormat(data.lastmodified)#">
</cffunction>
</cfcomponent>
JMSGateway
The JMSGateway class acts as a Java Messaging Service consumer or producer. The source for this event gateway is
located in gateway/src/examples/JMS. The gateway requires a configuration file, which is in
gateway/config/jmsgateway.cfg. For full documentation of the configuration options, See the configuration file. The
ColdFusion Administrator lists the compiled gateway (which is included in the gateway\lib\examples.jar file) on the
Gateway Types page.
Note: The ColdFusion Administrator uses JMS as the gateway type name for the JMSGateway class.
Using the JMS Gateway as a consumer
The JMSGateway class creates a subscriber to the topic specified in the configuration file. The gateway consumes the
following types of messages:
TextMessage
BytesMessage containing raw UTF-8 text
The gateway passes the contents of the message to the configured CFC in the event structure, as follows:
Field
Contents
data.id
Message correlation ID
data.msg
gatewayType
originatorID
1275
The listener CFC method must be named onIncomingMessage. If the CFC method does not send a message in
response, it should return a structure containing a status field with a value of OK or EXCEPTION. (In this case, The
gateway checks the return status field, but does not process these return values further.) To send a message, the CFC
method must return a structure as documented in the following section.
Using the JMS Gateway as a producer
To send a JMS message, the return value of your CFC method or the second, messageStruct, parameter to the
SendGatewayMessage function must be a structure with the following fields:
Field
Contents
status
Must be SEND.
topic
id
(Optional) The JMS correlation ID to associate with the message. The default is null.
message
asBytes
If you send the message in a SendGatewayMessage function, the function returns OK if the gateway sends the
message, or EXCEPTION if it fails to send the message.
ActiveMQ JMS event gateway
Apache ActiveMQ is a message broker that implements JMS. The source for this event gateway is located in
gateway/src/examples/ActiveMQ. For information about using the ActiveMQ JMS event gateway, see the
gateway\docs\ActiveMQDeveloperGuide.pdf file.
The Gateway Instances page in the ColdFusion Administrator includes a gateway instance for this application that
uses the SMS gateway type.
The gateway/cfc/examples/menu directory and its subdirectories include the CFML for the application
The gateway/config/sms-test.cfg file is configured to use this application with the SMS client (phone simulator),
and short message service center (SMSC) server simulator that are provided with ColdFusion.
The application presents users with a drill-down menu of tools that they can use, including a weather report, stock
information, status and configuration information, and language tools such as a dictionary.
The code for this application is relatively complex and is distributed among 13 files. The following brief description
provides an overview of how it works. To get a full understanding of how the application works, see the source code.
The top level, menu, directory contains two files: Application.cfm and main.cfc.
The Application.cfm file consists of a single cfapplication tag that enables session management and names the
application. Session variables maintain the current state information of the session, such as the active menu, and so on.
1276
The main.cfc file contains the master CFC; the event gateway configuration in ColdFusion Administrator uses it as
the listener CFC. The main CFC file processes CFEvent structures from the event gateway. It does the following:
1 Inspects the gatewayType field to determine the rest of the structure contents. This check is necessary because
different event gateways place the message in fields with different names.
2 If a Session.menu variable does not exist, initializes the menu system. To do so, it calls methods in two other
CFCs: menu and menunode. These two CFCs contain the menu system code.
3 Calls the session.menu.process method to process the user input. This method can dispatch a message to an
The apps directory contains several CFCs. Each file contains the code for a single application, such as the weather
report or dictionary lookup (definition.cfc).
Use the menu application with the Socket event gateway
1 On the Gateway Settings page in the ColdFusion Administrator, click the Start SMS Test Server button.
2 On the Gateway Instances page in the ColdFusion Administrator, start the SMS Menu App - 5551212 event gateway
by clicking the green play button (third button from the left in the Actions column). If the Status does not say
Running after a few seconds, click Refresh to check that the server started.
3 In the cf_root\WEB-INF\cfusion\bin directory on J2EE configurations or the cf_root\bin directory on server
configurations, run the SMSClient.bat file (on Windows) or SMSClient.sh file (on UNIX or Linux) to start the SMS
phone simulator. The simulator is preconfigured by default to call the default SMS event gateway configuration.
4 Enter any character by typing or by using the mouse to click the simulator keypad, and press Enter on your
thesaurus, S to get stock quotes or weather forecasts, or C to get information about the server. Press Enter on your
keyboard or click Send on the simulator.
6 The application displays a submenu. For example, if you select S in step 5, the options are Q for a stock quote, W
dictionary, and so on. Enter and send the required information (or enter B to go back to the menu).
8 The application gets and displays the requested information. Depending on the application, you could also be
prompted to enter M to get more. Enter M (if more information is available), another term, or B to return to the
previous menu.
9 Continue by entering menu items and detailed information requests.
10 To exit, select File > Exit from the menu bar.
1277
About XMPP
XMPP (Extensible Messaging and Presence Protocol) is an open, XML-based protocol for instant messaging. It is the
core protocol of the Jabber Instant Messaging and Presence technology that the Jabber Software Foundation develops.
As of November 2004, four Internet Engineering Task Force (IETF) specifications (RFCs) defined XMPP, numbers
3920-3923. RFC 3920 covers the XMPP core, and 3921 covers instant messaging and presence. Numerous XMPP
servers and clients are available. ColdFusion supports the IETF XMPP protocol.
The following websites provide additional information about the XMPP protocol:
Jabber Software Foundation: www.jabber.org/. This site includes information on available XMPP servers and
clients.
You implement your IM application by configuring a gateway instance in ColdFusion Administrator that uses one of
these gateway classes and creating a ColdFusion application that uses the gateway instance to communicate with an
instant messaging server.
1278
Message type
onIncomingMessage
onAddBuddyRequest
onAddBuddyResponse
Responses from others to requests from your gateway to add them to your buddy lists. Also used by
buddies to ask to be removed from your list.
onBuddyStatus
onIMServerMessage
For more information on these methods, see Handling incoming messages on page 1280.
1279
IMGatewayHelper methods
The ColdFusion IM gateway provides the IMGatewayHelper class, a gateway helper that you can access by calling the
CFML GetGatewayHelper function. The IMGatewayHelper class has methods that let you do the following:
Get and set gateway configuration information and get gateway statistics
Get and set the gateway online presence status
Manage the gateways buddy list
Manage permissions for others to get information about the gateway status.
For more information on using GatewayHelper methods, including lists of all the methods, see Using the
GatewayHelper object on page 1287.
Default value
Description
userID
none
password
none
secureprotocol
none
XMPP only.
Required if you set securerequirement to true.
The protocol to use for secure communications. The following values are valid:
securerequirement
false
TSL
SSL
XMPP only.
Specifies whether the gateway must use secure communications. The following values
are valid:
true
false
If this value is true, specify a secureprotocol value, and connections succeed only if
a secure connection is established.
serverip
XMPP: jabber.org
Sametime:
stdemo3.dfw.ibm.com
serverport
Address of XMPP or Lotus Sametime server to which to send messages. Can be a server
name or IP address.
XMPP: 5222
Sametime:1533
1280
Property
Default value
Description
retries
-1
Integer number of times to retry connecting to the IM server on gateway startup or if the
Gateway gets disconnected.
0 = do not to retry
-1 = try forever
retryinterval
onIncomingMessageFu
nction
onIncomingMessage
Name of CFC method to call to handle an incoming message. If you specify the property
without a value, such as onIncomingMessageFunction=, the gateway does not send
this event to a CFC.
onAddBuddyRequestFu
nction
onAddBuddyRequest
Name of CFC method to call to handle an incoming buddy request. If you specify the
property without a value, the gateway does not send this event to a CFC.
onAddBuddyResponseF
unction
onAddBuddyResponse
Name of CFC method to call to handle an incoming response to a buddy request sent by
ColdFusion. If you specify the property without a value, the gateway does not send this
event to a CFC.
onBuddyStatusFunction onBuddyStatus
Name of CFC method to call to handle an incoming buddy status message, such as If you
specify the property without a value, the gateway does not send this event to a CFC.
onIMServerMessageFun
ction
Name of CFC method to call to handle an incoming message method. If you specify the
property without a value, the gateway does not send this event to a CFC.
onIMServerMessage
Note: If you do not have a CFC method to handle any of the event types, specify the corresponding property without a
value. Use the following entry in the configuration file, for example, if you do not have a method to handle
IMServerMessage events: onIMServerMessageFunction=
Description
onIncomingMessage
Standard message from an IM user. The application processes the message body appropriately; for
example, it could display the message in an interface window.
This method can return a response message to the sender.
onAddBuddyRequest
Request from another IM user to add your applications IM ID to their buddy list. The CFC must
determine whether to accept or reject the request, or to take no action. An action is not always
appropriate in cases where the request must be reviewed offline for approval and responses are
sent at a later time.
The CFC returns a message with the decision as a command value and optionally a text message
specifying the reason. If you accept the request, the requestor automatically gets added to the list
of IDs that can get status information for the gateway. If you specify no action, ColdFusion does not
respond.
1281
CFC method
Description
onAddBuddyResponse
Response from another IM user to a request from the gatewaybeing added to their buddy list. The
response message is accept or decline.
Your application can handle this response as appropriate; for example, to add or remove the ID
from a list of message recipients.
This method does not return a value.
onBuddyStatus
Message indicating a gateway buddys status. Received when a buddys status changes; for
example, from OFFLINE to ONLINE.
This method does not return a value.
onIMServerMessage
Status messages from the IM server, such as warning or error messages. The messages you can
receive depend on the IM server that sends them. For information on the server messages, see the
documentation for the IM server that your gateway instance uses.
This method does not return a value.
For detailed information on each method, including examples of their use, see IM Gateway CFC incoming message
methods in the CFML Reference. For an example that uses these functions, see Sample IM message handling
application on page 1282.
Description
submit
accept
Accepts an add buddy request. Adds the buddy to the list of IDs that get your presence information and sends an
acceptance message to the buddy ID.
decline
Declines an add buddy request and sends a rejection message to the buddy ID.
noact
Tells the gateway to take no action. The gateway logs a message that indicates that it took no action, and contains the
gateway type, gateway ID, and buddy ID.
The message structure that you return in the gateway listener CFC function or use as the second parameter in the
CFML SendGatewayMessage function can have the following fields. The table lists the fields and the commands in
which they are used, and describes each fields use.
Field
Commands
Description
buddyID
All
command
All
message
submit
reason
accept, decline
A text description of the reason for the action or other message to send to the add buddy
requestor.
In typical use, a ColdFusion application uses the accept, decline, and noact commands in the return value of the
onAddBuddyRequest method, and uses the submit command (or no command, because submit is the default
command) in SendGatewayMessage CFML functions and the return value of the onIncomingMessage CFC method.
1282
The SendGatewayMessage CFML function can send any command, and can be used to send an accept or decline
message. One possible use is in an application where someone must review all buddy requests before they are added.
In this case, the onAddBuddyRequest CFC method could initially send a noact command in its return value, and save
the request information in a database. Administrators could use a separate ColdFusion application to review the
request information. This application could use the SendGatewayMessage function with an accept or decline
command to act on the request and inform the requestor.
The following example onIncomingMessage method of a listener CFC echoes incoming IM messages to the message
originator:
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset retValue.MESSAGE = "echoing: " & CFEvent.DATA.message>
<cfset retValue.BuddyID = arguments.CFEVENT.DATA.SENDER>
<cfreturn retValue>
</cffunction>
If there is no match, the onIncomingMessage function returns a message indicating that there are no matches.
If there is one match, the function returns the name, department, and phone number.
If there are up to ten matches, the function returns a list of the names preceded by a number that the user can enter
to get the detailed information.
If there are over ten matches, the function returns a list of only the first ten names. A more complex application can
let the user get multiple lists of messages to provide access to all names.
If the user enters a number, and previously got a multiple-match list, the application returns the information for
the name that corresponds to the number.
The following listing shows the CFC code:
1283
<cfcomponent>
<cffunction name="onIncomingMessage">
<cfargument name="CFEvent" type="struct" required="YES">
<!--- Remove any extra white space from the message. --->
<cfset message =Trim(arguments.CFEvent.data.MESSAGE)>
<!--- If the message is numeric, a previous search probably returned a
list of names. Get the name to search for from the name list stored in
the Session scope. --->
<cfif isNumeric(message)>
<cfscript>
if (structKeyExists(session.users, val(message))) {
message = session.users[val(message)];
}
</cfscript>
</cfif>
<!--- Search the database for the requested name. --->
<cfquery name="employees" datasource="cfdocexamples">
select FirstName, LastName, Department, Phone
from Employees
where 0 = 0
<!--- A space indicates the user entered a first and last name. --->
<cfif listlen(message, " ") eq 2>
and FirstName like '#listFirst(message, " ")#%'
and LastName like '#listlast(message, " ")#%'
<!--- No space: the user entered a first or a last name. --->
<cfelse>
and (FirstName like '#listFirst(message, " ")#%'
or LastName like '#listFirst(message, " ")#%')
</cfif>
</cfquery>
<!--- Generate andreturn the message.--->
<cfscript>
retrunVal = structNew();
retrunVal.command = "submit";
retrunVal.buddyID = arguments.CFEvent.data.SENDER;
//No records were found.
if (employees.recordCount eq 0) {
retrunVal.message = "No records found for '#message#'";
}
//One record was found.
else if (employees.recordCount eq 1) {
// Whitespace in the message text results in bad formatting,
// so the source cannot be indented.
retrunVal.message = "Requested information:
#employees.firstName# #employees.lastName#
#employees.Department#
#employees.Phone#";
}
//Multiple possibilities were found.
else if (employees.recordCount gt 1) {
//If more than ten were found, return only the first ten.
if (employees.recordCount gt 10)
{
retrunVal.message = "First 10 of #employees.recordCount# records";
1284
}else{
retrunVal.message = "Records found: #employees.recordCount#";
}
// The session.users structure contains the found names.
// The record key is a number that is also returned in front of the
// name in the message.
session.users = structNew();
for(i=1; i lte min(10, employees.recordCount); i=i+1)
{
// These two lines are formatted to prevent extra white space.
retrunVal.message = retrunVal.message & "
#i# - #employees.firstName[i]# #employees.lastName[i]#";
// The following two lines must be a single line in the source
session.users[i]="#employees.firstName[i]#
#employees.lastName[i]#";
}
}
return retrunVal;
</cfscript>
</cffunction>
</cfcomponent>
The onBuddyStatus function updates the Application scope buddy status structure when the gateway gets an event
message indicating that a buddys status has changed.
The onAddBuddyRequest function searches for the requested buddys name in a data source. If it finds a single
instance of the name, it adds the buddy and updates the status in the Application scope buddyStatus structure. If it
doesnt find name, it declines the buddy request. If it finds multiple instances of the name, it tells the gateway to
take no action. It also logs all actions.
The onAddBuddyResponse function adds the buddy to the Application scope buddy status structure if the buddy
request is accepted, and sets the current status. It logs all responses.
1285
<cfcomponent>
<cffunction name="onBuddyStatus">
<cfargument name="CFEvent" type="struct" required="YES">
<cflock scope="APPLICATION" timeout="10" type="EXCLUSIVE">
<cfscript>
// Create the status structures if they don't exist.
if (NOT StructKeyExists(Application, "buddyStatus")) {
Application.buddyStatus=StructNew();
}
if (NOT StructKeyExists(Application.buddyStatus, CFEvent.Data.BUDDYNAME)) {
Application.buddyStatus[#CFEvent.Data.BUDDYNAME#]=StructNew();
}
// Save the buddy status and timestamp.
Application.buddyStatus[#CFEvent.Data.BUDDYNAME#].status=CFEvent.Data.BUDDYSTATUS;
Application.buddyStatus[#CFEvent.Data.BUDDYNAME#].timeStamp=CFEvent.Data.TIMESTAMP;
</cfscript>
</cflock>
</cffunction>
<cffunction name="onAddBuddyRequest">
<cfargument name="CFEvent" type="struct" required="YES">
<cfquery name="buddysearch" datasource="cfdocexamples">
select IM_ID
from Employees
where IM_ID = '#CFEvent.Data.SENDER#'
</cfquery>
<cflock scope="APPLICATION" timeout="10" type="EXCLUSIVE">
<cfscript>
// If the name is in the DB once, accept; if it is missing, decline.
// If it is in the DB multiple times, take no action.
if (buddysearch.RecordCount IS 0) {
action="decline";
reason="Invalid ID";
}
else if (buddysearch.RecordCount IS 1) {
action="accept";
reason="Valid ID";
//Add the buddy to the buddy status structure only if accepted.
if (NOT StructKeyExists(Application,
"buddyStatus")) {
Application.buddyStatus=StructNew();
}
if (NOT StructKeyExists(Application.buddyStatus,
CFEvent.Data.SENDER)) {
Application.buddyStatus[#CFEvent.Data.SENDER#]=StructNew();
}
Application.buddyStatus[#CFEvent.Data.SENDER#].status=
"Accepted Buddy Request";
Application.buddyStatus[#CFEvent.Data.SENDER#].timeStamp=
CFEvent.Data.TIMESTAMP;
Application.buddyStatus[#CFEvent.Data.SENDER#].message=
CFEvent.Data.MESSAGE;
}
else {
1286
action="noact";
reason="Duplicate ID";
}
</cfscript>
</cflock>
<!--- Log the request and decision information. --->
<cflog file="#CFEvent.GatewayID#Status"
text="onAddBuddyRequest; SENDER: #CFEvent.Data.SENDER# MESSAGE:
#CFEvent.Data.MESSAGE# TIMESTAMP: #CFEvent.Data.TIMESTAMP# ACTION: #action#">
<!--- Return the action decision. --->
<cfset retValue = structNew()>
<cfset retValue.command = action>
<cfset retValue.BuddyID = CFEvent.DATA.SENDER>
<cfset retValue.Reason = reason>
<cfreturn retValue>
</cffunction>
<cffunction name="onAddBuddyResponse">
<cfargument name="CFEvent" type="struct" required="YES">
<cflock scope="APPLICATION" timeout="10" type="EXCLUSIVE">
<cfscript>
//Do the following only if the buddy accepted the request.
if (NOT StructKeyExists(Application, "buddyStatus")) {
Application.buddyStatus=StructNew();
}
if (#CFEVENT.Data.MESSAGE# IS "accept") {
//Create a new entry in the buddyStatus record for the buddy.
if (NOT StructKeyExists(Application.buddyStatus,
CFEvent.Data.SENDER)) {
Application.buddyStatus[#CFEvent.Data.SENDER#]=StructNew();
}
//Set the buddy status information to indicate buddy was added.
Application.buddyStatus[#CFEvent.Data.SENDER#].status=
"Buddy accepted us";
Application.buddyStatus[#CFEvent.Data.SENDER#].timeStamp=
CFEvent.Data.TIMESTAMP;
Application.buddyStatus[#CFEvent.Data.SENDER#].message=
CFEvent.Data.MESSAGE;
}
</cfscript>
</cflock>
<!--- Log the information for all responses. --->
<cflog file="#CFEvent.GatewayID#Status"
text="onAddBuddyResponse; BUDDY: #CFEvent.Data.SENDER# RESPONSE:
#CFEvent.Data.MESSAGE# TIMESTAMP: #CFEvent.Data.TIMESTAMP#">
</cffunction>
<cffunction name="onIMServerMessage">
<!--- This function just logs the message. --->
<cfargument name="CFEvent" type="struct" required="YES">
<cflog file="#CFEvent.GatewayID#Status"
text="onIMServerMEssage; SENDER: #CFEvent.OriginatorID# MESSAGE:
#CFEvent.Data.MESSAGE# TIMESTAMP: #CFEvent.Data.TIMESTAMP#">
</cffunction>
</cfcomponent>
1287
Get and set gateway configuration information and get gateway statistics.
Get and set the gateway online status.
Manage the gateways buddy list
Manage permissions for others to get information about the gateway status.
The following sections briefly describe the class methods. For detailed information about each method, see IM
Gateway GatewayHelper class methods in the CFML Reference.
Description
getName
getNickName
getProtocolName
Returns the name of the instant messaging protocol (JABBER for XMPP, or SAMETIME).
numberOfMessagesReceived
Returns the number of messages received by the gateway since it was started.
numberOfMessagesSent
Returns the number of messages sent by the gateway since it was started.
setNickName
Description
getCustomAwayMessage
Returns the gateways custom away message if the setStatus method set it.
getStatusAsString
getStatusTimeStamp
Returns the date/time that the gateway changed its online status.
isOnline
Returns True if the gateway is connected to the IM server; otherwise, returns false.
setStatus
Description
addBuddy
Adds a buddy to the gateways buddy list and tells the IM server to send the gateway messages with
the buddys online state.
1288
Method
Description
getBuddyInfo
Gets information about the specified user from the buddy list, deny list, and permit list.
getBuddyList
removeBuddy
Removes the specified user name from the gateways buddy list and tells the IM server to stop
sending the gateway messages with the users online state.
Description
addDeny
Tells the IM server to add the specified user to the gateways deny list. If the permitMode is
DENY_SOME, these users cannot receive messages on the gateways state.
addPermit
Tells the IM server to add the specified user to the servers permit list. If the permitMode is
PERMIT_SOME, these users receive messages on the gateways state.
getDenyList
Returns the list of users that the server has been told not to send state information to.
getPermitList
Returns the list of users that the server has been told to send state information to.
getPermitMode
Gets the gateways permit mode from the IM server. The permit mode determines whether all users
can get the gateways online state information, or whether the server uses a permit list or a deny list
to control which users get state information.
removeDeny
removePermit
setPermitMode
GatewayHelper example
This example lets you use the XMPP or SameTime GatewayHelper class to get and set status and other information,
including managing buddy lists and view permissions lists.
1289
1290
</cfloop>
</select>
<input type="text" name="custommsg" value="(custom away massage)" size="30"/>
<input type="submit"/>
</form>
<li>
<form action="#cgi.script_name#" method="get">
setNickName:
<input type="hidden" name="cmd" value="setnickname">
<input type="text" name="nickname" value="(enter nickname)">
<input type="submit">
</form>
--->
<li>INFO: <a href="#cgi.script_name#?cmd=getname">getname</a> |
<a href="#cgi.script_name#?cmd=getnickname">getnickname</a> |
<a href="#cgi.script_name#?cmd=getcustomawaymessage">getcustomawaymessage</a> |
<a href="#cgi.script_name#?cmd=getprotocolname">getprotocolname</a> |
<a href="#cgi.script_name#?cmd=getstatusasstring">getstatusasstring</a> |
<a href="#cgi.script_name#?cmd=isonline">isonline</a>
<li>MESSAGE COUNT:
<a
href="#cgi.script_name#?cmd=numberofmessagesreceived">numberofmessagesreceived</a> |
<a href="#cgi.script_name#?cmd=numberofmessagessent">numberofmessagessent</a>
<li>RUNNING TIME: <a
href="#cgi.script_name#?cmd=getsignontimestamp">getsignontimestamp</a> |
<a href="#cgi.script_name#?cmd=getstatustimestamp">getstatustimestamp</a>
<li>setPermitMode:
<cfloop
list="PERMIT_ALL,DENY_ALL,PERMIT_SOME,DENY_SOME,IGNORE_IN_LIST,IGNORE_NOT_IN_LIST"
index="e"><a href="#cgi.script_name#?cmd=setpermitmode&mode=#e#">#e#</a> |
</cfloop> <span class="note">doesn't work for XMPP</span>
<li><a href="#cgi.script_name#?cmd=getpermitmode">getpermitmode</a>
<li>setPlainTextMode:
<cfloop list="PLAIN_TEXT,RICH_TEXT" index="e">
<a href="#cgi.script_name#?cmd=setplaintextmode&mode=#e#">#e#</a> |
</cfloop>
<li><a href="#cgi.script_name#?cmd=getplaintextmode">getplaintextmode</a>
</ul>
</cfoutput>
<!--- The url.cmd value exists if one of the previous links or forms has been submitted, and
identifies the type of request. --->
<cfoutput>
<cfif isdefined("url.cmd")>
<!--- Get the GatewayHelper for the gateway. --->
<cfset helper = getGatewayHelper(session.gwid)>
<!--- Get the buddy list if the list or full buddy information was requested. --->
<cfswitch expression="#LCase(url.cmd)#">
<cfcase value="buddylist,buddyinfo">
<cfset ret=helper.getBuddyList()>
</cfcase>
<cfcase value="denylist">
<cfset ret=helper.getDenyList()>
</cfcase>
<cfcase value="permitlist">
<cfset ret=helper.getPermitList()>
</cfcase>
1291
<cfcase value="addbuddy">
<cfset ret=helper.addBuddy("#session.buddyid#",
"#session.buddyid#", "")>
</cfcase>
<cfcase value="addpermit">
<cfset ret=helper.addPermit("#session.buddyid#",
"#session.buddyid#", "")>
</cfcase>
<cfcase value="adddeny">
<cfset ret=helper.addDeny("#session.buddyid#",
"#session.buddyid#", "")>
</cfcase>
<cfcase value="removebuddy">
<cfset ret=helper.removeBuddy("#session.buddyid#", "")>
</cfcase>
<cfcase value="removepermit">
<cfset ret=helper.removePermit("#session.buddyid#", "")>
</cfcase>
<cfcase value="removedeny">
<cfset ret=helper.removeDeny("#session.buddyid#", "")>
</cfcase>
<cfcase value="setstatus">
<cfset ret=helper.setStatus(url.status, "")>
</cfcase>
<cfcase value="setstatus2">
<cfset ret=helper.setStatus(url.status, url.custommsg)>
</cfcase>
<cfcase value="getcustomawaymessage">
<cfset ret=helper.getCustomAwayMessage()>
</cfcase>
<cfcase value="getname">
<cfset ret=helper.getName()>
</cfcase>
<cfcase value="getnickname">
<cfset ret=helper.getNickname()>
</cfcase>
<cfcase value="getprotocolname">
<cfset ret=helper.getProtocolName()>
</cfcase>
<cfcase value="getsignontimestamp">
<cfset ret=helper.getSignOnTimeStamp()>
</cfcase>
<cfcase value="getstatusasstring">
<cfset ret=helper.getStatusAsString()>
</cfcase>
<cfcase value="getstatustimestamp">
<cfset ret=helper.getStatusTimeStamp()>
</cfcase>
<cfcase value="isonline">
<cfset ret=helper.isOnline()>
</cfcase>
<cfcase value="numberofmessagesreceived">
<cfset ret=helper.numberOfMessagesReceived()>
</cfcase>
<cfcase value="numberofmessagessent">
<cfset ret=helper.numberOfMessagesSent()>
</cfcase>
1292
<cfcase value="setnickname">
<cfset ret=helper.setNickName(url.nickname)>
</cfcase>
<cfcase value="setpermitmode">
<cfset ret=helper.setPermitMode(url.mode)>
</cfcase>
<cfcase value="getpermitmode">
<cfset ret=helper.getPermitMode()>
</cfcase>
<cfcase value="setplaintextmode">
<cfset ret=helper.setPlainTextMode(url.mode)>
</cfcase>
<cfcase value="getplaintextmode">
<cfset ret=helper.getPlainTextMode()>
</cfcase>
<cfdefaultcase>
<cfset ret[1]="Error; Invalid command. You shouldn't get this.">
</cfdefaultcase>
</cfswitch>
<br>
<!--- Display the results returned by the called GatewayHelper method. --->
<strong>#url.cmd#</strong><br>
<cfdump var="#ret#">
<br>
<!--- If buddy information was requested, loop through buddy list to get
information for each buddy and display it. --->
<cfif comparenocase(url.cmd, "buddyinfo") is 0 and arraylen(ret) gt 0>
<b>Buddy info for all buddies</b><br>
<cfloop index="i" from="1" to="#arraylen(ret)#">
<cfdump var="#helper.getBuddyInfo(ret[i])#" label="#ret[i]#"></cfloop>
</cfif>
</cfif>
</cfoutput>
1293
Notifying users of events such as package shipments or restaurant table availability, or providing stock or weather
alerts
About SMS
The following discussion simplifies SMS technology and describes only a typical use with a ColdFusion application. For
a more complete discussion of SMS, see the publicly available literature, including the several books that discuss SMS.
In a ColdFusion SMS application, a mobile device such as a mobile phone communicates (via intermediate steps) with
a message center, such as a short message service center (SMSC). For example, a mobile phone user calls a telephone
number that the SMS provider has associated with your account; the SMSC gets the messages that are sent to this
number. The SMSC can store and forward messages. A ColdFusion application can initiate messages to wireless
devices, or it can respond to incoming messages from the devices.
The SMSC communicates with a ColdFusion SMS event gateway using short message peer-to-peer protocol (SMPP)
over TCP/IP. Information is transferred by exchanging Protocol Data Units (PDUs) with structures that depend on
the type of transaction, such as a normal message submission, a binary data submission, or a message intended for
multiple recipients.
Because the SMSC is a store-and-forward server, it can hold messages that cannot be immediately delivered and try to
deliver them when the receiving device is available. The SMSC provider configures the time that a message is held on
the server for delivery. For example, AT&T Wireless saves messages for 72 hours; after that time, any undelivered
messages are deleted. Your messages can request a different time-out (by specifying a ValidityPeriod field). The
message can also use a registeredDelivery field to tell the SMSC to inform you about whether and when the
message is delivered.
SMS communication can be secure. Voice and data communications, including SMS message traffic between the
SMSC and the mobile device is encrypted as part of the GSM standard. The SMSC authenticates the mobile user's
identity before the encrypted communication session begins. Secure the communications between ColdFusion and the
SMSC. Typically, you use a secure hardware or software VPN connection around the SMPP connection.
1294
The following image shows the SMS path between mobile devices and ColdFusion gateways:
SMS gateway
instance
SMPPTCP/IP
PP
SM P/IP
TC
Cell Phone
Carrier SMSC
SMS gateway
Instance
Wireless network
SMS Gateway
instance
ColdFusion
PDA
SMPPTCP/IP
Carrier SMSC
Telephone
Using the SMS event gateway, ColdFusion establishes a two-way (transceiver) connection to the SMSC of the
telecommunications carrier or other SMPP account provider. The SMPP provider assigns an address for your account,
and you associate an event gateway instance with the address. Addresses are normally telephone numbers, but carriers
often support short code addresses that do not require a full 10-digit number. You also configure the gateway
instance to communicate with the providers specified TCP/IP address using a system ID and a password.
Note: The ColdFusion SMS event gateway conforms to the SMPP 3.4 specification, which you can download from the
SMS Forum at www.smsforum.net.
A ColdFusion application can initiate and send messages to SMS-enabled devices by specifying the destination mobile
device telephone number, or mobile devices can send messages to a ColdFusion listener CFC by using the gateway
instances telephone number. Incoming messages include the senders number, so listener CFCs can respond to
messages sent by mobile devices.
You implement your SMS application by creating a ColdFusion application that uses an instance of the SMSGateway
class to communicate with one or more SMSCs. You can use the SMS testing server and client simulator to test your
application without requiring an outside SMS service provider.
1295
SMSC. Configure the gateway using the information supplied by your provider.
7 Test your application using the telecommunications providers SMSC and target mobile devices.
8 Make the application publicly available.
1296
command, and interactive applications such as those provided via a wireless application protocol (WAP) framework
typically use it.
The SMS gateway lets you control the contents of all of the fields of these PDUs. For more information on the
individual commands, see Sending outgoing messages on page 1300.
When you send a message, if the SMSC responds with a status that indicates that the message was rejected or not sent,
ColdFusion logs information about the failure in the eventgateway.log file. If the SMSC indicates that the service type
is not available (SMPP v5 ESME_RSERTYPUNAVAIL status or AT&T Serviced denied status), and the gateway
configuration file transient-retry value is set to yes, the gateway also tries to resend the message.
Outgoing message synchronization and notification
The gateway and SMSC communicate asynchronously: the gateway does not wait for a response from the SMSC for
one message before it sends another message. However, you can configure your gateway instance so that the CFML
sendGatewayMessage function behaves asynchronously or synchronously.
In asynchronous mode, the function returns when the message is queued in ColdFusion gateway services.
In synchronous mode, the function waits until the SMSC receives the message and returns a message ID, or an error
occurs.
For more information on configuring message synchronization and sending messages synchronously, see
Controlling SMS message sending and response on page 1303.
1297
Default
ip-address
port
Description
IP address of the SMSC, as specified by the SMPP provider. For the ColdFusion SMS test
server, you normally use 127.0.0.1.
Port number to bind to on the SMSC. The ColdFusion SMS test server uses port 7901.
system-id
Name that identifies the event gateway to the SMSC, as established with the SMPP provider.
To connect to the ColdFusion SMS test server, the system-id must be cf.
password
Password for authenticating the event gateway to the SMSC. To connect to the ColdFusion
SMS test server, the password must be cf.
source-ton
Type of Number (TON) of the source address, that is, of the address that the event gateway
uses for outgoing messages, as specified in the SMPP specification. Values include 0,
unknown; 1, international number; 2, national number.
source-npi
Numeric Plan Indicator (NPI) of the source address as specified in the SMPP specification.
Values include 0, unknown; 1, ISDN.
source-address
empty string
Address (normally, a phone number) of the event gateway. Identifies the sender of
outgoing messages to the SMSC.
addr-ton
TON for the incoming addresses that this event gateway serves.
addr-npi
NPI for the incoming addresses that this event gateway serves.
address-range
The range of incoming addresses (phone numbers) that remote devices can use to send
messages to the event gateway instance; often, the same as the source-address.
message-rate
100
Integer or decimal value that specifies the number of messages the gateway is allowed to
send to your service provider per second. 0 is unlimited.
mode
synchronous
synchronous The gateway waits for the response from the server when sending a
message. In this mode, the SendGatewayMessage CFML function returns the SMS
messageID of the message, or an empty string if an error occurs.
asynchronous
The gateway does not wait for a response. In this mode, the
network-retry
no
Gateway behavior when a network error occurs while trying to deliver a message:
yes The gateway queues the message for delivery when the gateway is able to rebind
to the SMSC. Retrying is useful if the gateway is in asynchronous mode, where the CFML
SendGatewayMessage function does not return an error.
1298
Property
Default
Description
transient-retry
no
Gateway behavior when the SMSC returns an error that indicates a transient error, where it
may be able to accept the message in the future:
yes The gateway attempts to resend the message. Retrying is useful if the gateway is in
asynchronous mode, where the CFML SendGatewayMessage function does not return
an error.
cfc-method
onIncomingMessage
Listener CFC method for ColdFusion to invoke when the gateway gets incoming messages.
destination-ton
destination-npi
service-type
empty string
Type of messaging service; can be empty or one of the following values: CMT, CPT, VMN,
VMA, WAP, or USSD.
system-type
empty string
Type of system (ESME, External Short Message Entity ); used when binding to the SMSC.
Some SMSCs might be able to send responses that are specific to a given type of ESME.
Normally set to SMPP.
receive-timeout
The time-out, in seconds, for trying to receive a message from the SMSC after it establishes
a connection. To wait indefinitely until a message is received, set the receive-timeout
to -1.
ping-interval
60
Number of seconds between EnquireLink messages that the event gateway sends to the
server to verify the health of the connection.
retries
-1 (try forever)
Number of times to retry connecting to the SMSC to send a message before the gateway
goes into a failed state. If the gateway is in a failed state, the getStatus method returns
FAILED, and theColdFusion Administrator shows the gateway status as Failed. The gateway
must be restarted before it can be used.
retry-interval
10
You can also set the following values in each outgoing message: source-ton, source-npi, source-address, destinationton, destination-npi, and service-type. The message field names differ from the configuration file property names.
1299
Field
Value
CfcMethod
Data.dataCoding
Data.destAddress
Data.esmClass
Message type
Data.MESSAGE
Message contents
Data.messageLength
Data.priority
Data.protocol
Data.registeredDelivery
Data.sourceAddress
GatewayType
Always SMS
OriginatorID
For a detailed description of each field, see SMS Gateway incoming message CFEvent structure in the CFML Reference.
The CFCs listener method extracts the message from the Arguments.CFEvent.Data.MESSAGE field and acts on it as
appropriate for the application. If necessary, the listener can use two fields to determine the required action:
CFEvent.Data.esmClass field
The CFEvent.Data.esmClass field identifies whether the CFEvent.Data.Message field contains a message, or any of the
following types of message disposition responses. For these responses, the CFEvent object Data.MESSAGE field
contains the acknowledgment or receipt information.
SMSC Delivery Receipt An indication of the messages final status, sent by the SMSC. The short message text includes
the message ID of the original message, the number of messages sent and delivered (for messages sent to a distribution
list), the date and time that the message was sent and delivered or otherwise disposed of, the message disposition, a
network-specific error code (if available), and the first 20 bytes of the message. For details of the SMSC delivery receipt
message structure, see Appendix B of the SMS 3.4 specification.
SME Delivery Acknowledgement An indication from the recipient device that the user has read the short message.
delivered, sent during the SMSC retry lifetime for the message. Intermediate Notification support depends on the
SMSC implementation and SMSC service provider. For more information, see your provider documentation.
When you send a message, you can request any combination of message disposition responses in the outgoing
messages registered_delivery parameter. If your application requests responses, the listener CFC must be
prepared to handle these messages, as appropriate.
1300
CFEvent.Data.registeredDelivery field
The CFEvent.Data.registeredDelivery field indicates whether the message sender has requested a receipt or
acknowledgment. Your application can respond to a request for an SME Delivery Acknowledgement or an SME
Manual/User Acknowledgement. (Only the SMSC sends the other notification types.) For more information on these
notification types, see the SMS 3.4 specification. Appendix B contains detailed information on the information that
you must place in the shortMessage field of the returned acknowledgment message.
Contents
command
If present, the value must be "submit". If you omit this field, the event gateway sends a submit message.
shortMessage
messagePayload
The Message contents. specify one of these fields, but not both. The SMPP specification imposes a maximum
size of 254 bytes on the shortMessage field, and some carriers could limit its size further. The
messagePayload field can contain up to 64 K bytes; it must start with 0x0424, followed by 2 bytes specifying
the payload length, followed by the message contents.
destAddress
sourceAddress
The address of this application. You can omit this field if it is specified in the configuration file.
or
1301
You can also set optional fields in the structure, such as a field that requests a delivery receipt. For a complete list of
fields, see submit command in the CFML Reference. For detailed descriptions of these fields, see the documentation
for the SUBMIT_MULTI PDU in the SMPP3.4 specification, which you can download from the SMS Forum at
www.smsforum.net/.
Note: To send long messages, you can separate the message into multiple chunks and use a submit command to send each
chunk separately. In this case, a CFC would use multiple SendGatewayMessage functions, instead of the cfreturn
function.
Example: Using the submit command in sendGatewayMessage function
The following example from a CFM page uses a sendGatewyMessage CFML function with a submit command to
send an SMS messages that you enter in the form. This example uses the SMS gateway that is configured in the
ColdFusion installation, and sends the message to the SMS client simulator.
<h3>Sending SMS From a Web Page Example</h3>
<cfif IsDefined("form.oncethrough") is "Yes">
<cfif IsDefined("form.SMSMessage") is True AND form.SMSMessage is not "">
<h3>Sending Text Message: </h3>
<cfoutput>#form.SMSMessage#</cfoutput><br>
<cfscript>
/* Create a structure that contains the message. */
msg = structNew();
msg.command = "submit";
msg.destAddress = "5551234";
msg.shortMessage = form.SMSMessage;
ret = sendGatewayMessage("SMS Menu App - 5551212", msg);
</cfscript>
</cfif>
<hr noshade>
</cfif>
<!--- begin by calling the cfform tag --->
<cfform action="command.cfm" method="POST">
SMS Text Message: <cfinput type="Text" name="SMSMessage" value="Sample text Message"
required="No" maxlength="160">
<p><input type = "submit" name = "submit" value = "Submit">
<input type = "hidden" name = "oncethrough" value = "Yes">
</cfform>
</body>
</html>
For a simple example of a listener CFC uses the submit command to echo incoming SMS messages to the message
originator, see Incoming message handling example on page 1300.
1302
Field
Contents
command
Must be "submitMulti".
shortMessage
messagePayload
The message contents. Specify one of these fields, but not both. The SMPP specification imposes a maximum size
of 254 bytes on the shortMessage field, and some carriers could limit its size further. The messagePayload
field can contain up to 64 K bytes; it must start with 0x0424, followed by 2 bytes specifying the payload length,
followed by the message contents.
destAddress
or
You cannot specify individual TON and NPI values for these addresses; all must conform to a single setting.
sourceAddress
The address of this application; you can omit this field if it is specified in the configuration file.
You can also set optional fields in the structure, such as a field that requests delivery receipts. For a complete list of
fields, see submitMulti command in the CFML Reference. For detailed descriptions of these fields, see the
documentation for the SUBMIT_MULTI PDU in the SMPP 3.4 specification, which you can download from the SMS
Forum at www.smsforum.net/.
Example: Using the submitMulti command in an onIncomingMessage method
The following example onIncomingMessage method sends a response that echoes an incoming message to the
originator address, and sends a copy of the response to a second address. To test the example, run two instances of the
ColdFusion SMS client application. Use the default phone number of 5551212 for the first, and set the second one to
have a phone number of 555-1235. (Notice that the second phone number requires a hyphen (-).) Send a message from
the first simulator, and the response appears in both windows.
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<!--- Get the message. --->
<cfset data=CFEvent.DATA>
<cfset message="#data.message#">
<!--- Create the return structure. --->
<cfset retValue = structNew()>
<cfset retValue.command = "submitmulti">
<cfset retValue.sourceAddress = arguments.CFEVENT.gatewayid>
<cfset retValue.destAddresses=arraynew(1)>
<!--- One destination is incoming message originator;
get the address from CFEvent originator ID. --->
<cfset retValue.destAddresses[1] = arguments.CFEvent.originatorid>
<cfset retValue.destAddresses[2] = "555-1235">
<cfset retValue.shortMessage = "echo: " & message>
<cfreturn retValue>
</cffunction>
</cffunction>
Contents
command
Must be "data" .
1303
Field
Contents
messagePayload
Message data. To convert data to binary format, use the ColdFusion toBinary function.
destAddress
sourceAddress
You can also set optional fields in the structure, such as a field that requests a delivery receipt. For a complete list of
fields, see data command in the CFML Reference. For detailed descriptions of these fields, see the documentation for
the SUBMIT_MULTI PDU in the SMPP3.4 specification, which you can download from the SMS Forum at
www.smsforum.net/.
Example: Using the data command
The following example onIncomingMessage method converts an incoming message to binary data, and sends the
binary version of the message back to the originator address:
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<!--- Get the message. --->
<cfset data=CFEvent.DATA>
<cfset message="#data.message#">
<!--- Create the return structure. --->
<cfset retValue = structNew()>
<cfset retValue.command = "data">
<!--- Sending to incoming message originator; get value from CFEvent. --->
<cfset retValue.destAddress = arguments.CFEvent.originatorid>
<cfset retValue.messagePayload = tobinary(tobase64("echo: " & message))>
<cfreturn retValue>
</cffunction>
If you specify asynchronous mode, the sendGatewayMessage function returns an empty string when the gateway
submits the message to service code for sending to the SMSC. ColdFusion logs errors that occur after this point,
such as if a message sent by the gateway to the SMSC times out or if the gateway gets an error response; the
application does not get notified of any errors.
If you specify synchronous mode (the default), the sendGatewayMessage function does not return until the
gateway gets a response from the SMSC or the attempt to communicate times out. If the message is sent
successfully, the function returns the SMPP message ID string. If an error occurs, the function returns an error
string.
Use synchronous mode if your application must determine whether its messages reach the SMSC. Also use
synchronous mode if the application requests return receipts.
Note: If you use synchronous mode and the SMSC returns the messgeID as a hexadecimal string, ColdFusion converts it
automatically to its decimal value.
1304
The following example is an expansion of Example: Using the submit command in sendGatewayMessage function
discussed in The submit command on page 1300. It checks for a nonempty return value and displays the message
number returned by the SMS. This example uses the SMS gateway that is configured when ColdFusion is installed. If
you change the gateway specified in the SendGatewayMessage function, make sure that your gateways configuration
file specifies synchronous mode.
<h3>Sending SMS From a Web Page Example</h3>
<cfif IsDefined("form.oncethrough") is "Yes">
<cfif IsDefined("form.SMSMessage") is True AND form.SMSMessage is not "">
<h3>Sending a Text Message: </h3>
<cfoutput>#form.SMSMessage#</cfoutput><br><br>
<cfscript>
/* Create a structure that contains the message. */
msg = structNew();
msg.command = "submit";
msg.destAddress = "5551234";
msg.shortMessage = form.SMSMessage;
ret = sendGatewayMessage("SMS Menu App - 5551212", msg);
</cfscript>
</cfif>
<cfif isDefined("ret") AND ret NEQ "">
<h3>Text message sent</h3>
<cfoutput>The Message Id is: #ret#</cfoutput>
<br><br>
</cfif>
<hr noshade>
</cfif>
<!--- begin by calling the cfform tag --->
<cfform>
SMS Text Message: <cfinput type="Text" name="SMSMessage"
value="Sample text Message" required="No" maxlength="160">
<p><input type = "submit" name = "submit" value = "Submit">
<input type = "hidden" name = "oncethrough" value = "Yes">
</cfform>
1305
If there is only one optional parameter, you can instead use the following code:
out.optionalParameter=parameter;
out.optionalParameterValue="value";
Note: Ensure that the Java Short.decode(String) function can parse the key or the value is a byte.
Message disposition notification
You can request the SMSC to return a message disposition response to indicate the fate of your message. To request a
delivery receipt, include a RegisteredDelivery field in the Data parameter of a SendGatewayMessage function or the
return variable of the CFC listener method. This field can have the following values:
Value
Meaning
Some providers also support intermediate delivery notifications. For more information, see your providers
documentation.
To use delivery notification, send your message using synchronous mode, so you get a message ID. Your incoming
message routine must be able to handle the receipts (see Handling incoming messages on page 1298).
Validity period
You can change the length of time that the SMSC keeps a message and tries to deliver it. (Often the default value is 72
hours.) For a message sent to an emergency worker, for example, a short validity period (such as 15 min.) can be
appropriate. To change this value, include a validityPeriod field in the Data parameter of a SendGatewayMessage
function or the return variable of the CFC listener method. To specify a time period, use the following pattern:
YYMMDDhhmmsst00R. In this pattern, t indicates tenths of seconds, and 00R specifies that this value is a relative time
period, not a date-time value. The time format 000001063000000R, for example, specifies a validity period of 0 years,
0 months, 1 day, 6 hours, 30 minutes.
1306
The SMS test server lets you develop SMS applications without having to use an external SMSC supplier such as a
telecommunications provider. The server supports the ColdFusion SMS gateway submit and submitMulti
commands. It also accepts, but does not deliver messages sent using the SMS gateway data command. It does not
include any store and forward capabilities.
Start the SMS test server by clicking the Start SMS Test Server button on the Settings page in the Event Gateways area
in the ColdFusion Administrator.
Note: The SMS test server does not automatically restart when you restart ColdFusion. Manually restart the server if you
restart ColdFusion.
The SMS test server reads the cf_root\WEB-INF\cfusion\lib\sms-test-users.txt file on J2EE configurations or
cf_root\lib\sms-test-users.txt file on server configurations to get valid user names and passwords. ColdFusion includes
a version of this file configured with several names and passwords. One valid combination is user name cf and
password cf. You can edit this file to add or delete entries. The file must include a name and password entry for each
user that connects to the test server. Separate user entries with blank lines, as the following example shows:
name=cf
password=cf
name=user1
password=user1
INF\cfusion\bin directory on J2EE configurations and the cf_root\bin directory on server configurations.
If you installed a pure Java version of ColdFusion, for example, on Apple Mac OS X systems, enter the following
command to start the simulator:
java -jar cf_root/WEB-INF/cfusion/lib/smpp.jar
3 A dialog box appears, requesting the server, port, user name, password, and the phone number to use for this
device. The simulator sends this phone number as the source address, and accepts SMS messages sent by the SMSC
server to it using this number as the destination address.
To connect to the SMS test server, accept the default values and specify an arbitrary phone number; you can also
specify any user name-password pair that is configured in the cf_root\WEB-INF\cfusion\lib\sms-test-users.cfg file
or cf_root\lib\sms-test-users.cfg or file.
4 Click Connect.
5 The SMS device simulator client appears. In the Send SMS To field, enter a phone number in the address-range
property specified in the configuration file of the SMS event gateway that you want to send messages to.
6 Type a message directly into the message field (to the left of the Send button), or use the simulator keypad to enter
the message.
1307
The client simulator has a Connection menu with options to connect and disconnect from the SMSC server, and to
check the connection. The connection information appears in a status line at the bottom of the client.
If no match exists, the onIncomingMessage function returns a message indicating that no matches exist.
If one match exists, the function returns the name, department, and phone number.
If up to ten matches exist, the function returns a list of the names preceded by a number that the user can enter to
get the detailed information.
If over ten matches exist, the function returns a list of only the first ten names. A more complex application could
let the user get multiple lists of messages to provide access to all names.
If the user enters a number, and previously got a multiple-match list, the application returns the information for
the name that corresponds to the number.
The following listing shows the CFC code:
<cfcomponent>
<cffunction name="onIncomingMessage">
<cfargument name="CFEvent" type="struct" required="YES">
<!--- Remove any extra white space from the message. --->
<cfset message =Trim(arguments.CFEvent.data.MESSAGE)>
<!--- If the message is numeric, a previous search probably returned a
list of names. Get the name to search for from the name list stored in
the Session scope. --->
<cfif isNumeric(message)>
<cfscript>
if (structKeyExists(session.users, val(message))) {
message = session.users[val(message)];
}
</cfscript>
</cfif>
<!--- Search the database for the requested name. --->
<cfquery name="employees" datasource="cfdocexamples">
select FirstName, LastName, Department, Phone
from Employees
where 0 = 0
<!--- A space indicates the user entered a first and last name. --->
<cfif listlen(message, " ") eq 2>
and FirstName like '#listFirst(message, " ")#%'
and LastName like '#listlast(message, " ")#%'
<!--- No space: the user entered a first or a last name. --->
<cfelse>
and (FirstName like '#listFirst(message, " ")#%'
or LastName like '#listFirst(message, " ")#%')
</cfif>
</cfquery>
<!--- Generate andreturn the message.--->
1308
<cfscript>
returnVal = structNew();
returnVal.command = "submit";
returnVal.sourceAddress = arguments.CFEVENT.gatewayid;
returnVal.destAddress = arguments.CFEVENT.originatorid;
//No records were found.
if (employees.recordCount eq 0) {
returnVal.shortMessage = "No records found for '#message#'";
}
//One record was found.
else if (employees.recordCount eq 1) {
// Whitespace in the message text results in bad formatting,
// so the source cannot be indented.
returnVal.shortMessage = "Requested information:
#employees.firstName# #employees.lastName#
#employees.Department#
#employees.Phone#";
}
//Multiple possibilities were found.
else if (employees.recordCount gt 1) {
//If more than ten were found, return only the first ten.
if (employees.recordCount gt 10)
{
returnVal.shortMessage = "First 10 of #employees.recordCount# records";
}else{
returnVal.shortMessage = "Records found: #employees.recordCount#";
}
// The session.users structure contains the found names.
// The record key is a number that is also returned in front of the
// name in the message.
session.users = structNew();
for(i=1; i lte min(10, employees.recordCount); i=i+1)
{
// These two lines are formatted to prevent extra white space.
returnVal.shortMessage = returnVal.shortMessage & "
#i# - #employees.firstName[i]# #employees.lastName[i]#";
// The following two lines must be a single line in the source
session.users[i]="#employees.firstName[i]# #employees.lastName[i]#";
}
}
return returnVal;
</cfscript>
</cffunction>
</cfcomponent>
1309
Video on Demand
Live web-event broadcasts
Mp3 streaming
Video blogging
Video messaging
Multimedia chat environments
To learn more about and to download the Flash Media Server, go to the Adobe website. at
www.adobe.com/go/learn_cfu_flashmediaserver_en.
How ColdFusion and Flash Media Server interact through the FMS gateway
The FMS event gateway lets you modify data through the ColdFusion application or the Flash client, and reflect the
change in the Flash Media Server shared object. The FMS event gateway listens to the shared object, and notifies
ColdFusion when other clients modify shared objects. The FMS event gateway also lets ColdFusion modify shared
objects.
ColdFusion provides the following tools for developing FMS applications:
FCSj.jar The JAR file that implements the Java API to communicate with Flash Media Server.
FMSGateway The class for the FMS event gateway type. You implement your FMS application by creating a
ColdFusion application that uses an instance of the FMSGateway class to communicate with one or more Flash Media
Server.
perform all actions required, including notifying the FMS Gateway Helper to update the shared object.
5 The FMS Gateway Helper sends a message to the FMS event gateway to update the shared object.
6 The FMS event gateway updates the shared object.
7 Flash Media Server notifies all the Flash clients that it modified the shared object. As a result, the Flash clients reflect
the change.
1310
The following image shows the interaction between Flash Media Server, the FMS event gateway, and the ColdFusion
application:
1.
Flash client
Flash client
10.
ColdFusion Server
Sales Data So
Sales Data List
Changed Sales Data
9.
3.
4.
8.
FMS_gateway.cfc
FMS Gateway Helper
7.
database
6.
5.
sales.cfc
application.
5 Test your application using Flash Media Server and the Flash client.
6 Make the application publicly available.
1311
Description
setProperty
Sets the property of the Flash Media Server shared object. The following parameters are valid:
name: The string that contains the name of the shared object.
value: The shared object.
getProperty
Gets the property of the Flash Media Server shared object. The following parameters are valid:
name: The string that contains the name of the shared object.
Data translation
ColdFusion and Flash Media Server use different data types; therefore, data translation is required to pass data from
one to the other. In addition to basic data types such as numeric, String, and Boolean, you can pass ColdFusion queries,
structures, and arrays to Flash Media Server. You pass a ColdFusion query object to Flash Media Server as an array of
java.util.HashMap. Each HashMap object in the array contains a key-value pair for column names and values for each
row in the query. When you pass a ColdFusion array to Flash Media Server, the FMS event gateway converts it to a
Java array of objects. When you pass a ColdFusion structure, no conversion is required.
The FMS event gateway does not support passing CFCs in shared objects.
1312
the appropriate ColdFusion values and add the message to the event gateway queue.y
5 The ColdFusion server calls the onIncomingMessage method of the Data Services Messaging event gateway listener CFC.
6 The ColdFusion application generates a message, which it sends to the ColdFusion server.
7 The ColdFusion server sends the message to the Data Services Messaging event gateway.
8 The Data Services Messaging event gateway and the ActionScript translator convert ColdFusion values to the
appropriate ActionScript 3.0 data types and then the gateway sends the message to the ColdFusion Event Gateway
Adapter.
9 The ColdFusion Event Gateway Adapter sends the message to the Flex Message Service.
10 The Flex Message Service passes the message to the Flex application.
Note: The RMI registry, which facilitates communication between the ColdFusion Event Gateway Adapter and the Data
Services Messaging event gateway uses port 1099, which is the default port for Java RMI. You cannot change this port
number. To ensure that the RMI registry provides registry service for both LiveCycle Data Services and ColdFusion, start
LiveCycle Data Services first, and then start ColdFusion. If you stop Flex, restart LiveCycle Data Services, and then restart
the gateway.
1313
Have the Data Services Messaging event gateway send messages to Flex Enterprise Services 2 on a different
computer
Use the Data Services Messaging event gateway with a specific Flex destination, and ignore any destination
specified in the message
The Data Services Messaging event gateway configuration file is a simple Java properties file that contains the following
properties:
Property
Description
destination
A hard-coded destination. If you specify this value, any destination information in the message is ignored.
host
If you create a configuration file, save it in the cf_root/gateway/config/ directory, with the extension .cfg.
In outgoing messages sent from CFML, the following structure members are translated to the Flex message:
Name
Contents
body
CorrelationID
Destination
Flex destination of the message. Required if it is not specified in the configuration file.
Headers
If the message contains any headers, the CFML structure that contains the header names as keys and values.
LowercaseKeys
If the value is set to yes, the structure keys are converted to lowercase during creation of ActionScript types.
TimeToLive
1314
In addition, the Data Services Messaging event gateway automatically provides values for the following Flex message
fields:
Name
Contents
MessageID
Timestamp
ClientID
Note: A single instance of the Data Services Messaging event gateway can send messages to any destination that is
registered with the ColdFusion Event Gateway Adapter. However, if the destination is configured in the Data Services
Messaging gateway configuration file, the destination in the message is ignored.
success = StructNew()>
success.msg = "E-mail was sent at " & Now()>
success.Destination = "gateway1">
ret = SendGatewayMessage("Flex2CF2", success)>
To ensure that properties maintain the correct case, define Flex-related information as follows:
myStruct['mySensitiveProp']['myOtherSensitiveProp']
The following is an example of using headers to send to a specific subtopic of the destination:
<cfset
<cfset
<cfset
<cfset
<cfset
Contents
body
ClientID
CorrelationID
Destination
Headers
If the message contains any headers, the CFML structure that contains the header names as keys and values.
Timestamp
The incoming message data structure also includes the values of messageID and timeToLive from the Flex message.
1315
If the Flex application sends the message in the header instead of in the body, you create and populate the structure,
as the following example shows:
<cfset
<cfset
<cfset
<cfset
<cfset
messageheader = StructNew()>
messageheader.sendto = event.data.headers.emailto>
messageheader.sentfrom = event.data.headers.emailfrom>
messageheader.subject = event.data.headers.emailsubject>
messageheader.mailmsg = event.data.headers.emailmessage>
<cfset
<cfset
<cfset
<cfset
mailfrom="#messageheader.sentfrom#">
mailto="#messageheader.sendto#">
mailsubject="#messageheader.subject#">
mailmessage ="#messageheader.mailmsg#">
allowSend
allowSubscribe
Data translation
The following table lists the ColdFusion data types and the corresponding Flash or ActionScript data type:
1316
String
String
Array
[] = Array
Struct
{} = untyped Object
Query
ArrayCollection
CFC
Class = typed Object (if a matching ActionScript class exists, otherwise the CFC becomes a
generic untyped Object (map) in ActionScript)
CFC Date
ActionScript Date
CFC String
ActionScript String
CFC Numeric
ActionScript Numeric
ColdFusion
application
ColdFusion
server
LiveCycle
Data Services
event
gateway
ActionScript
translator
ColdFusion
Data
Service
Adapter
Message
Service
1 The ColdFusion application generates a message, which it sends to the ColdFusion server.
Flex
application
1317
2 The ColdFusion server sends the message to the Data Management event gateway.
3 The Data Management event gateway and the ActionScript translator convert ColdFusion values to the appropriate
ActionScript 3.0 data types, and then the gateway sends the message to the ColdFusion Data Service Adapter.
4 The ColdFusion Data Service Adapter sends the message to the LiveCycle Data Services Message Service.
5 The Message Service passes the message to the Flex application.
If you are running LiveCycle Data Services ES on the ColdFusion server, communication between LiveCycle Data
Services ES and ColdFusion does not use RMI.
If you are running LiveCycle Data Services ES remotely, to ensure that the RMI registry provides registry service
for both LiveCycle Data Services ES and ColdFusion, start LiveCycle Data Services ES first, and then start
ColdFusion. If you stop LiveCycle Data Services ES, restart LiveCycle Data Services ES, and then restart the
gateway.
If you are running LiveCycle Data Services ES remotely, the RMI registry, which facilitates communication between
the ColdFusion Data Service Adapter and the Data Management event gateway uses port 1099. This port is the
default value for Java RMI. You can change the port number by adding -Dcoldfusion.rmiport=1234, replacing
1234 with the appropriate port number, to the Java JVM arguments on both the ColdFusion server and the Flex
server.
Have the Data Management event gateway send messages to LiveCycle Data Services ES on a different computer.
Use the Data Management event gateway with a specific Flex destination, and ignore any destination specified in
the message.
The Data Management event gateway configuration file is a simple Java properties file that contains the following
properties:
Property
Description
destination
A hard-coded destination. If you specify this value, any destination information in the message is ignored.
host
The host name or IP address of the LiveCycle Data Services ES server. Omit the host name if you are running
LiveCycle Data Services ES as part of ColdFusion.
1318
#
# Data Management event gateway configuration
#
# This is the destination where messages are sent.
destination=myDestination
# Host name or IP address of the LiveCycle Data Services ES Server
host=127.0.0.1
If you create a configuration file, save it in the cf_root/gateway/config/ directory, with the extension .cfg.
Note: A single instance of the Data Management event gateway can send messages to any destination that is registered
with the ColdFusion Data Service Adapter. However, if the destination is configured in the Data Management event
gateway configuration file, the destination in the message is ignored.
Sending messages
Your ColdFusion application sends a message to a Flex application by calling the ColdFusion SendGatewayMessage
function. In messages sent from CFML, the following structure members are translated to the Flex message:
Name
Contents
destination
Destination of the message. This entry is required if it is not specified in the configuration file.
action
Required. The notification action that is being performed: create, delete, deleteID, refreshfill, or
update.
item
Required when action="create" or action="delete". The record that was added or deleted.
identity
Required when action="deleteID". A structure that contains the identity properties (primary key) of the
record that was deleted.
fillparameters
Optional. An array that contains the fills parameters that specify which fill operations to refresh.
newversion
previousversion
Optional. The previous record, before the update. This entry is used for conflict resolution.
changes
Optional when action="update". A comma-delimited list or array of property names that were updated in
the record. If you omit this entry, ColdFusion assumes that all properties changed. When you change a large
number of records, you specifying the property names can improve performance.
Required when action="batch". An array of structures that contain the changes. You can batch multiple
changes and send them in a single notification. The changes can be of different types, for example five updates,
one delete, and two creates. Each event structure must contain an action.
Example
The following example creates a structure for each event type. It then creates a structure that contains the message. The
message structure contains an array of event structures to send to Flex. The destination is the destination ID specified
in the flex-services.xml file for the instance of the Data Management event gateway to send the message to. The body
is the body of the message. The sendGatewyMessage CFML function sends the message to the instance of the gateway.
1319
<cfscript>
// Create event
createEvent = StructNew();
createEvent.action = "create";
createEvent.item = newContact;
// Create update notification
updateEvent = StructNew();
updateEvent.action="update";
updateEvent.previousversion = oldContact;
updateEvent.newversion = updatedContact;
// Create delete notification
identity = StructNew();
identity["contactId"] = newId;
deleteEvent = StructNew();
deleteEvent.action = "deleteID";
deleteEvent.identity = identity;
// Send a batch notification
all = StructNew();
all.destination="cfcontact";
all.action="batch";
all.changes = ArrayNew(1);
all.changes[1] = createEvent;
all.changes[2] = updateEvent;
all.changes[3] = deleteEvent;
r = sendGatewayMessage("LCDS", all);
</cfscript>
Data translation
The following table lists the ColdFusion data types and the corresponding Adobe Flash or ActionScript data type:
ColdFusion data type
String
String
Array
[] = Array
Struct
{} = untyped Object
Query
ArrayCollection
CFC
Class = typed Object (if a matching ActionScript class exists, otherwise the CFC becomes a
generic untyped Object (map) in ActionScript)
CFC Date
ActionScript Date
CFC String
ActionScript String
CFC Numeric
ActionScript Numeric
1320
event
Listener thread
addEvent
method
CFEvent
Message
CFEvent
Listener
CFC
event
outgoingMessage
method
.
.
.
.
CFEvent
.
.
.
External event
generator /
receiver
CFEvent
event
event
Event Gateway
.
.
.
ColdFusion
Event
Gateway
Services
Event Gateway
CFEvent
Listener
CFC
CFEvent
CFC
Message
Applicat
CFML
Page
Application
Receiving messages: The event gateway listener thread receives events from an external event source such as a socket
or SMSC server, and calls the GatewayServices addEvent method to send a CFEvent instance to ColdFusion.
Sending messages: The ColdFusion event gateway service calls the outgoingMessage method of the event gateway
and passes it a CFEvent instance with the destination and message information. The event gateway forwards the
message as appropriate to the external receiver.
The event gateway architecture is not limited to handling messages from external sources, such as SMS devices or IM
clients. It can also be used to handle events that are internal to the local system or even the ColdFusion application.
Also, a gateway does not have to implement two-way communications.
The sample directory watcher gateway provided with ColdFusion is an example of an internal, one way, gateway. It
has a single thread that periodically checks a local directory and sends a message to a CFC when the directory contents
change. This gateway does not support outgoing messages. (The code for this gateway is in the
gateway/src/examples/watcher directory.)
Another internal gateway, the asynchronous CFML gateway, is provided as part of the ColdFusion product. Unlike
most gateways, it does not have a listener thread. Its outgoingMessage method gets messages from CFML
SendGatewayMessage functions, and dispatches them to a CFC onIncomingMessage method for handling. This
gateway lets ColdFusion support request-free asynchronous processing. For more information on using this gateway,
see Using the CFML event gateway for asynchronous CFCs on page 1269.
1321
Gateway interface
The ColdFusion event gateway must implement the coldfusion.eventservice.Gateway interface. The following table
lists the interface method signatures:
Note: For detailed information on implementing each method, see Building an event gateway on page 1325. For
reference pages for these methods, see Gateway interface in the CFML Reference.
Signature
Description
Sets the gateway ID that uniquely identifies the gateway instance. ColdFusion
calls this method before it starts the event gateway, even if the gateway class
constructor also sets the ID.
Identifies the CFCs that listen for incoming messages from the event gateway.
The array contains one or more paths to the listener CFCs. ColdFusion calls this
method before it starts the event gateway, and if the configuration for a running
event gateway changes.
GatewayHelper getHelper()
String getGatewayID()
int getStatus()
Gets the event gateway status. The interface defines the following status
constants: STARTING, RUNNING, STOPPING, STOPPED, FAILED.
void start()
Starts the event gateway. Starts at least one thread for processing incoming
messages. ColdFusion calls this method when it starts an event gateway.
void stop()
Stops the event gateway. Stops the threads and destroys any resources.
ColdFusion calls this method when it stops an event gateway.
void restart()
Restarts a running event gateway. ColdFusion calls this method when the
ColdFusion Administrator restarts a running event gateway.
1322
GatewayServices class
The Gateway class uses the coldfusion.eventgateway.GatewayServices class to interact with the ColdFusion event
gateway services. This class has the following methods:
Signature
Description
GatewayServices getGatewayServices
Static method that returns the GatewayServices object. Gateway code can call
this method at any time, if necessary.
boolean addEventmsg)
int getQueueSize
Returns the current size of the ColdFusion event queue. This queue handles all
messages for all gateways.
int getMaxQueueSize
Returns the maximum size of the ColdFusion event queue, as set in the
ColdFusion Administrator.
Logger getLogger
Returns a ColdFusion Logger object that the event gateway can use to log
information in the eventgateway.log log file (the default) or the specified log file.
Logger getLoggerlogfile)
CFEvent class
The Gateway class sends and receives CFEvent instances to communicate with the ColdFusion listener CFC or
application. The Gateway notifies ColdFusion of a message by sending a CFEvent instance in a
GatewayServices.addEvent method. Similarly, the Gateway receives a CFEvent instance when ColdFusion calls the
gateway outgoingMessage method.
The CFEvent class extends the java.util.Hashtable class and has the following methods to construct the instance and
set and get its fields. (In CFML, you treat CFEvent instances as structures.)
Methods
Description
CFEventgatewayID)
CFEvent constructor. The gatewayID parameter must be the value that is passed
in the gateway constructor or set using the Gateway setGatewayID method.
void setGatewayTypetype)
Identifies the type of event gateway, such as SMS. For the sake of consistency,
use this name in the Type Name field when you add an event gateway type on
the Gateway Types page in the ColdFusion Administrator.
String getGatewayType
void setDatadata)
Map getData
The event data; includes the message being passed to or from ColdFusion. The
content of the field depends on the event gateway type. The Map keys must be
strings.
Because ColdFusion is not case sensitive, it converts the Map passed in the
setData method to a case-insensitive Map. As a result, do not create entries in
the data with names that differ only in case.
void setOriginatorIDid)
String getOriginatorID
void setCFCPathpath)
String getCFCPath
1323
Methods
Description
void setCFCMethodmethod)
The method in the listener CFC that ColdFusion calls to process this event. By
default, ColdFusion calls the onIncomingMessage method. For the sake of
consistency, Adobe recommends that any event gateway with a single listener
does not override this default. A gateway, such as the ColdFusion XMPP
gateway, that uses different listener methods for different message types, uses
this method to identify the destination method.
String getCFCMethod
void setCFCTimeoutseconds)
String getCFCTimeout
String getGatewayID
The time-out, in seconds, for the listener CFC to process the event request.
When ColdFusion calls the listener CFC to process the event, and the CFC does
not process the event in the specified time-out period, ColdFusion terminates
the request and logs an error in the application.log file. By default, ColdFusion
uses the Timeout Request value set on the Server Settings page in the
ColdFusion Administrator.
The event gateway instance that processes the event. Returns the gateway ID
that was set in the CFEvent constructor.
GatewayHelper class
ColdFusion includes a coldfusion.eventgateway.GatewayHelper Java marker interface. You implement this interface
to define a class that provides gateway-specific utility methods to the ColdFusion application or listener CFC. For
example, an instant messaging event gateway could use a helper class to provide buddy list management methods to
the application.
The Gateway class must implement a getHelper method that returns the helper class or null (if the gateway does not
need such a class).
ColdFusion applications call the GetGatewayHelper CFML function, which calls gateways the getHelper method to
get an instance of the helper class. The application can then call helper class methods using ColdFusion object dot
notation.
The following code defines the SocketHelper class, the gateway helper for the SocketGateway class. It has an empty
constructor and two public methods: one returns the socket IDs; the other closes a specified socket. These classes let
an application monitor and end session connections.
1324
The example SocketGateway event gateway uses this technique to get an optional port number from a configuration
file. For an example of reading a properties file and using its data, see the code in Class constructor on page 1325.
The coldfusion.eventgateway.GenericGateway class is an abstract class from which you can derive your gateway
class.
The EmptyGateway class in the gateway\src\examples directory is a template gateway that you can complete to
create your gateway class.
1325
outgoingMessage
If you support a configuration file, a constructor that takes a configuration file, and configuration loading routines.
If you use a gatewayHelper class, the getHelper method.
If the event source status can change asynchronously from the gateway, the getStatus method.
The example JMS gateway is derived from the generic gateway class. The gateway class JavaDocs in the gateway\docs
directory provide documentation for this class. (The CFML Reference does not document this class.)
The EmptyGateway class
The gateway\src\examples\EmptyGateway.java file contains an event gateway template that you can use as a skeleton
for creating your own event gateway. (The gateway directory is in the cf_root directory in the server configuration and
the cf_root\WEB-INF-cfusion directory on J2EE configurations.) This file contains minimal versions of all methods in
the coldfusion.eventgateway.Gateway interface. It defines a skeleton listener thread and initializes commonly used
Gateway properties. The EmptyGateway source code includes comments that describe the additional information that
you must provide to complete an event gateway class.
Class constructor
An event gateway can implement any of the following constructors:
MyGateway(String gatewayID)
MyGateway()
When ColdFusion starts, it calls the constructor for each event gateway instance that you configure in ColdFusion.
(ColdFusion also calls the gateway Start method after the event gateway is instantiated.). ColdFusion first attempts
to use the two-parameter constructor.
1326
Because each event gateway instance must have a unique ID, ColdFusion provides redundant support for providing
the ID. If the event gateway implements only the default constructor, ColdFusion provides the ID by calling the
setGatewayID method of the event gateway.
If the event gateway does not implement the two-parameter constructor, it does not get configuration file information
from ColdFusion.
The constructor normally calls the static GatewayServices.getGatewayServices method to access ColdFusion event
gateway services. Although you need not make this call, it is a good coding practice.
A minimal constructor that takes only a gateway ID could look like the following:
public MyGateway(String gatewayID) {
this.gatewayID = gatewayID;
this.gatewayService = GatewayServices.getGatewayServices();
}
The gateway constructor must throw a coldfusion.server.ServiceRuntimeException exception if an error occurs that
otherwise cannot be handled. For example, throw this exception if the event gateway requires a configuration file and
cannot read the file contents.
If your gateway uses a configuration file, have the constructor load the file, even if the Start method also loads the file.
Load the file because the constructor does not run in an independent thread, and ColdFusion can display an error in
the ColdFusion Administrator of the file fails to load. If the Start method, which does run in a separate thread, fails
to load the file, ColdFusion logs the error, but it cannot provide immediate feedback in the administrator.
The sample Socket event gateway has a single constructor that takes two parameters. It tries to load a configuration
file. If you specify a configuration file in the ColdFusion Administrator, or the file path is invalid, it gets an IO
exception. It then uses the default port and logs a message indicating what it did. The following example shows the
Gateway constructor code and the loadProperties method it uses:
public SocketGateway(String id, String configpath)
{
gatewayID = id;
gatewayService = GatewayServices.getGatewayServices();
// log things to socket-gateway.log in the CF log directory
log = gatewayService.getLogger("socket-gateway");
propsFilePath=configpath;
try
{
FileInputStream propsFile = new FileInputStream(propsFilePath);
properties.load(propsFile);
propsFile.close();
this.loadProperties();
}
catch (IOException e)
{
// Use default value for port and log the status.
log.warn("SocketGateway(" + gatewayID + ") Unable to read configuration
file '" + propsFilePath + "': " + e.toString() + ".Using default port
" + port + ".", e);
}
}
private void loadProperties() {
String tmp = properties.getProperty("port");
port = Integer.parseInt(tmp);
}
1327
setCFCListeners
setGatewayID
getHelper
getGatewayID
getStatus
ColdFusion calls the setCFCListeners method with the CFC or CFCs that are specified in the ColdFusion
Administrator when it starts a gateway. ColdFusion also calls the method in a running event gateway when the
configuration information changes, so the method must be written to handle such changes. The setCFCListeners
method must save the listener information so that the gateway code that dispatches incoming messages to gateway
services can use the listener CFCs in setCFCPath methods.
ColdFusion calls the setGatewayID method when it starts a gateway. The getGatewayID method must return the
value set by this method.
ColdFusion calls the getHelper method when an application calls the CFML GetGatewayHelper function.
The following code shows how the SocketGateway class defines these methods. To create a gateway, modify the
getHelper definition to return the correct class, or to return null if no gateway helper class exists. Most gateways can
leave the other method definitions unchanged.
public void setCFCListeners(String[] listeners) {
this.listeners = listeners;
}
public GatewayHelper getHelper() {
// SocketHelper class implements the GatewayHelper interface.
return new SocketHelper();
}
public void setGatewayID(String id) {
gatewayID = id;
}
public String getGatewayID() {
return gatewayID;
}
public int getStatus() {
return status;
}
1328
The start method should return within a time-out period that you can configure for each event gateway type in the
ColdFusion Administrator. If it does not, the ColdFusion Administrator has a Kill on Startup Timeout option for each
gateway type. If you select the option, and a time-out occurs, the ColdFusion starter thread calls an interrupt on the
gateway thread to try to kill it, and then exits.
Note: If the start method is the listener (for example, in a single-threaded gateway), the method does not return until
the gateway stops. Do not set the Kill on Startup Timeout option in the ColdFusion Administrator for such gateways.
If the gateway uses a configuration file, load the configuration from the file. Doing so lets users change the
configuration file and restart the gateway without restarting ColdFusion. Also load the configuration file in the
constructor; for more information, see Class constructor on page 1325.
In the SocketGateway class, the start method starts an initial thread. (In a single-threaded Gateway, this thread would
be the only one.) When the thread starts, it calls a socketServer method, which uses the Java ServerSocket class to
implement a multi-threaded socket listener and message dispatcher. For more information on the listener, see
Responding to incoming messages on page 1329.
public void start()
{
status = STARTING;
listening=true;
// Start up event generator thread
Runnable r = new Runnable()
{
public void run()
{
socketServer();
}
};
Thread t = new Thread(r);
t.start();
status = RUNNING;
}
1329
1330
3 Call the CFEvent setOriginator method to specify the source of the message. (This call is required if the
method to replace the default listener CFC. (For information on default CFEvent fields, see CFEvent class on
page 1322.)
6 Call the gatewayService.addEvent method to dispatch the CFEvent instance to ColdFusion.
7 Handle cases where the event is not added to the event gateway service queue (the addEvent method returns False).
If your application sends any messages to multiple listener CFCs, the gateway must create and configure a CFEvent
instance and call the gatewayService.addEvent method to send the message to each separate listener CFC. The
setCFCListeners method of the gateway must make the CFC paths available to the gateway for configuring the
CFEvent instances.
If your ColdFusion server carries a heavy event gateway message load, the ColdFusion event gateway services event
queue could reach the maximum value set in the ColdFusion Administrator. When the queue reaches the maximum,
the gatewayService.addEvent method returns False and fails. Your code can do any of the following:
Return a message to the sender to indicate that their message was not received.
Wait until the queue is available by periodically comparing the values returned by the GatewayService
getQueueSize and getMaxQueueSize methods, and retry the addEvent method when the queue size is less than
the maximum.
Log the occurrence using the logger returned by the GatewayService getLogger method. (For more information,
see Logging events and using log files on page 1332.)
The SocketGateway class implements the listener using a java.net.ServerSocket class object and SocketServerThread
listener threads. (See the SocketGateway source for the SocketServerThread code.) When the listener thread gets a
message from the TCP/IP socket, it calls the following processInput method to dispatch the message to ColdFusion.
This method explicitly sets all required and optional CFEvent fields and sends the event to ColdFusion. If the
addEvent call fails, it logs the error.
Note: Much of the processInput method code supports multiple listener CFCs. A gateway that uses only a single listener
CFC, would require only the code in the latter part of this method.
1331
1332
CFEvent instances returned from listener CFC onIncomingMessage methods include the originator ID of the
incoming message and other information. However, a gateway that could handle messages from the ColdFusion
SendGatewayMessage function cannot rely on this information being available, so it is good practice to require that
all outgoing messages include the destination ID in the data Map.
The outgoingMessage method returns a String value. The CFML sendGatewayMessage function returns this value
to the ColdFusion application. Indicate the status of the message in the returned string. By convention, ColdFusion
event gateway outgoingMessage methods return OK if they do not encounter errors and do not have additional
information (such as a message ID) to return.
Because event messages are asynchronous, a positive return normally does not indicate that the message was successful
delivered, only that the outgoingMessage method successfully handled the message. In some cases, however, it is
possible to make the outgoingMessage method at least partially synchronous. The SMS gateway, for example,
provides two outgoingMessage modes:
Asynchronous mode The outgoingMessage method returns when the message is queued internally for delivery to the
short message service center (SMSC) of the messaging provider.
Synchronous mode The method does not return until the message is delivered to the SMSC, or an error occurs.
This way, an SMS application can get a message ID for later use, such as to compare with a message receipt.
Example outgoingMessage method
The following outgoingMessage method is like the version in the SocketGateway class. It does the following:
1 Gets the contents of a MESSAGE field of the Data Map returned by the CFEvent class getData method.
2 Gets the destination from an outDestID field in the data Map.
3 Uses the socket server thread of the destination to write the message.
public String outgoingMessage(coldfusion.eventgateway.CFEvent cfmsg) {
String retcode="ok";
// Get the table of data returned from the event handler
Map data = cfmsg.getData();
String message = (String) data.get("MESSAGE");
// Find the right socket to write to from the socketRegistry hash table
// and call the writeoutput method of the socket thread.
// (Get the destination ID from the data map.)
if (data.get("outDestID") != null)
((SocketServerThread)socketRegistry.get(data.get("outDestID"))).
writeOutput(message);
else {
System.out.println("cannot send outgoing message. OriginatorID is not
available.");
retcode="failed";
}
return retcode;
}
1333
The following example tells ColdFusion to log messages from the gateway to the mygateway.log file in the ColdFusion
logs directory:
coldfusion.eventgateway.Logger log =getGatewayServices().getLogger("mygateway");
The Logger class has the following methods, all of which take a message string. The method you use determines
severity level that is set in the log message.
info
warn
error
fatal
You can also pass these methods an exception instance as a second parameter. When you pass an exception,
ColdFusion places the exception information in the exception.log file in the ColdFusion logs directory.
You can use these methods to log any messages that you find appropriate. If you use the default eventgateway.log file,
however, remember that all ColdFusion standard gateways us it, and other gateways could use it. As a result, limit the
messages that you normally log to this file to infrequent normal occurrences (such as gateway startup and shutdown)
or errors for which you want to retain data.
ColdFusion uses the following format for the message text, so have your application follow this pattern:
GatewayType (Gateway ID) Message
The SMS event gateway, for example, includes the following exception catching code, which logs a general exception
messages and the exception name in the eventgateway.log file, and also (automatically) logs the exception in the
exceptions.log file:
catch(Exception e)
{
logger.error("SMSGateway (" + gatewayID + ") Exception while processing
incoming event: " + e, e);
}
Note: When you are developing an event gateway application, you can use the ColdFusion Log viewer to inspect your log
files and the standard ColdFusion log files, including the eventgateway.log file and exception.log file. You can use the
viewer to filter the display, for example, by selecting different severity levels, or searching for keywords.
Note: The ColdFusion class loader includes the gateway \lib directory on its classpath and includes any JAR files that
are in that directory on the class path.
2 Place the JAR file in the cf_root\WEB-INF\cfusion\gateway\lib directory on J2EE configurations or the
1334
5 On the Add/Edit ColdFusion Event Gateway Types form, enter a type name (for example, SMS for the SMS event
gateway), a description, and the full Java class name (for example, coldfusion.eventgateway.sms.SMSGateway for
the SMS event gateway). If appropriate, change the Startup Timeout settings from the default values.
6 Click the Add Type button to deploy the event gateway type in ColdFusion.
The following procedure describes how to configure an event gateway instance that uses the gateway type.
Eclipse RDS Support plug-in, which lets you access files and data sources on a ColdFusion server.
ColdFusion/Flex Application wizard, which lets you create master and detail pages in an application to create, read,
update, and delete records in a database.
ColdFusion/Ajax Application wizard, which lets you create master and detail pages that use Ajax elements in an
application to create, read, update, and delete records in a database.
RDS CRUD wizard, which lets you dynamically create a ColdFusion component (CFC) based on a table that is
registered in the ColdFusion Administrator on a ColdFusion server
ActionScript to CFC wizard, which lets you create a CFC based on an ActionScript class file.
CFC to ActionScript wizard, which lets you create an ActionScript file based on a CFC Value Object
Services Browser, which lets you browse CFCs, manage a list of web services, and generate the CFML code to invoke
a web service.
1335
For information about installing the ColdFusion Extensions for Eclipse, see Installing ColdFusion guide.
Configuring RDS
Before using RDS, you must configure ColdFusion servers.
Configure any ColdFusion servers that you want to connect to using RDS
1 In Flash Builder or Eclipse, select Window > Preferences > ColdFusion > RDS Configuration.
2 To configure the default localhost server, select localhost and specify the following:
Description
Host name (127.0.0.1)
Port number (8500 if you are using the built-in web server)
Context root, if necessary (For more information about the context root, see Installing ColdFusion guide.)
Password, which is the RDS password
3 To specify additional servers, click New, and specify the following:
Note: If you are using ColdFusion MX 7 or earlier, the message The RDS server was successfully contacted, but your
security credentials were invalid, appears. The message indicates that the password was not validated, even if it is correct.
Click OK to close the message.
Once you have configured the RDS connection to your CF servers, you can view the files, folders and data sources on
RDS servers. Each RDS server appears as a node in the RDS Fileview and Dataview, with the name you specified when
you configured the RDS server.
View files and folders or data sources do the following
1 In Flash Builder, select Window > Other Views. In Eclipse, select Window > Show View > Other.
1336
2 Select RDS.
3 To access the file system on the RDS server, select RDS Fileview.
4 To access data sources on the RDS server, select RDS Dataview.
Action
Refresh the active RDS server.
Note: RDS Eclipse Support does not support file operations such as copy and paste, drag and drop, and changing file
attributes. However, delete, save, save as, and rename are supported. Also, on ColdFusion servers after ColdFusion 5, the
date last modified field does not appear.
To rename a folder or file, right-click the folder or filename.
Name
Description
Refresh
Query Viewer
You can build queries using either the RDS Query Viewer or the Visual Query Builder. The RDS Visual Query Builder
is like the ColdFusion Report Builder Query Builder and the HomeSite Query Builder.
Build and execute a query using the RDS Query Viewer
1 Click the RDS Query Viewer icon on the RDS Dataview tab.
The RDS Query Viewer opens in its own tab, which means that if you have other documents open, the RDS Query
Viewer has focus.
2 Do one of the following:
Enter the SQL, and double-click the field names and table names as appropriate.
Click the Visual Query Builder button.
1337
For more information about using the Visual Query Builder, see Using Visual Query Builder on page 1337.
3 To try the query, click Execute query.
Build a SQL statement using the Table pane and the Properties panel
1 Expand a data source.
2 Double-click the columns to be named in the SELECT statement.
As you select columns, the Query Builder creates the SELECT statement in the area at the lower edge of the pane.
3 If you select columns from more than one table, you must specify the column or columns used to join them by
dragging a column from one table to the related column in the second table.
4 (Optional) Specify sort order by doing the following:
a Locate the column in the Properties panel.
b Click in the Sort Type cell of the column you want to sort by.
c Specify Ascending or Descending.
d (Optional) If you specify multiple sort columns, you specify precedence using the Sort Order cell.
5 (Optional) Specify selection criteria by doing the following:
a Locate the column in the Properties panel.
b Click in the Condition cell.
c Select WHERE.
d Specify WHERE clause criteria in the Criteria cell.
Note: If you specify selection criteria, the Query Builder creates a WHERE clause. To use an INNER JOIN or other
advanced selection criteria instead, you must code the SQL manually.
6 (Optional) To specify an aggregate function, GROUP BY, or an expression:
a Locate the column in the Properties panel.
b Click in the Condition cell.
c Select Group By or the aggregate function (such as COUNT).
1338
7 (Optional) To specify SQL manually, type the SQL statement in the SQL pane.
Note: You code SQL manually to use an INNER JOIN instead of a WHERE clause, use an OUTER JOIN, or use a
database stored procedure.
8 (Optional) To specify the data type of a query parameter:
a Click the + button under Parameters.
b Enter the name of the parameter.
c Select the data type.
9 Review the SELECT statement that displays in the SQL pane, and use the Table and Properties panes to make
adjustments, if necessary.
10 (Optional) Click Test Query.
11 Click Save.
1339
select the configuration file, and then click Load ColdFusion/Flex Application Wizard Settings.
6 Click Next.
7 Select the RDS server on which you want the application to reside.
8 Specify the data source to use. The data source is configured in the ColdFusion Administrator.
Although you specify one default data source at this point, you can access data from other data sources in your
application.
9 Click Next.
Can link to
master
master
master/detail
detail
master and detail
master and master/detail
master/detail
master
master/detail
Create a page
1 Click the plus sign (+).
2 In the Name text box, enter the name for the page.
3 Select the page type (master, detail, or master/detail).
4 Click Edit Master Page, Edit Detail page, or Edit Master Section, depending on the type of form you are creating.
save the query. For more information about using Visual Query Builder, see Using Visual Query Builder on
page 1337.
6 Repeat steps 1 through 5 for each form in your application.
7 Use the right and left arrows to specify the relationship of the forms in your application. For example, detail forms
should appear indented, directly under the related master form in the Navigation Tree panel. You drag and drop
items to move them in the tree structure.
8 Click Next.
1340
The ColdFusion/Flex Application wizard creates the ColdFusion and Flex files that comprise your application. You
can test the application by clicking the Run Main button in Flash Builder or Eclipse, or by browsing to the main
application page, which is located at http://<server_name>:<port_number>/<project_name>/bin/main.html. You can
also manually modify the application files as appropriate for your needs.
To adjust UI elements, open the MXML file in Flash Builder or Eclipse design mode.
When you create a project that has the same name as a project you previously created, the wizard creates a backup
folder that contains the files from the project you previously created.
If you create a master page and a detail page for a table in which there is no primary key defined, the wizard selects
the first field in the database as the key value to represent the row.
In master pages, link a field to the Parameters box to add type validation to the query by using the cfqueryparam
tag. Doing this is optional.
You must select a primary key column in the master form; the wizard chooses the key by default. If you create a
master page and do not link it to the id property, you cannot add it to the site tree under another master page.
Deselect the Display column for fields that your application uses that you do not want to appear in your application.
Specify the sort order for the field by which to sort data in the page, and specify any other conditions as appropriate.
Change the labels for fields by clicking the field name in the Label column, and then entering a new field name.
In a detail page, create a combo box that is populated by dynamic data. To do this, change the value in the Input
Control column for the field to use to populate the combo box to be ComboBox, click the Input Lookup Query
(sub-select) column in that field, and then use the Visual Query Builder to specify the data to use.
When you create a detail page, display of the primary key is disabled automatically.
When you create a detail page, input controls are assigned by default. You can change them from the default values,
which appear as follows:
1341
location.
5 Enter the class package in the AS Class Package text box.
6 Enter the filename of the ActionScript class file in the AS Class Name text box.
7 To replace an existing file, select Overwrite file.
8 Enter the path to the CFC in the Path to CFC text box.
9 To create get and set methods in the ActionScript Class file, select Generate Get/Set Methods.
10 Click Finish.
1342
ActiveRecord style CRUD CFC, which includes all of the properties, get and set methods, and SQL methods in one
CFC. The CFC includes the following methods:
init() or init(primary key value)
load(primary key value)
save()
delete()
Data Service assembler CFC, which includes a Bean (also referred to as a Value Object), a DAO CFC, and an
assembler CFC. The assembler CFC is required to take advantage of the Flex Data Services feature
Primary Key is Controlled by the User option. If the primary key is automatically generated by the database (the
identity field), do not select this option.
8 To replace existing files, select the Overwrite Files If They Already Exist option.
9 Select one of the following CFC Types:
1343
location.
c To create get and set methods in the ActionScript Class file, select Generate Get/Set Methods.
12 Click Finish.
Services Browser
The ColdFusion Services Browser lets you view all of the CFCs and web services on your computer.
Browse components
Manage web services
Browsing components
The Service Browser lists the following components:
Components that are located in any directories specified in the ColdFusion Administrator Mappings page
Components that are located in any directories specified in the ColdFusion Administrator Custom Tag paths page
You can restrict the list of CFCs according to whether the functions in a CFC are remote, public, or private.
A sample element of the list appears as follows:
The first line of the listing contains the path. The second line includes the name of the CFC. The next two lines contain
the names of the functions in the CFC. The function name is followed by any argument, a colon, then the type of the
return value. The listing echo(echoString):STRING indicates that the echo function has an argument named
echoString, and that it returns a string. The myCFC CFC appears as follows:
1344
<cfcomponent>
<cffunction name="echo" output="No" returntype="string">
<cfargument name="echoString" required="Yes">
<cfreturn "echo: #arguments[1]#">
</cffunction>
<cffunction name="getArtists" returntype="query" hint="query the database and return the
results.">
<cfquery name="artists" datasource="cfcodeexplorer">
select *
from artists
</cfquery>
<cfreturn artists>
</cffunction>
</cfcomponent>
The code that the Service Browser generates appears in the ColdFusion file. The following is an example of the code
that the Service Browser generates:
<cfinvoke
webservice="http://arcweb.esri.com/services/v2/MapImage.wsdl"
method="convertMapCoordToPixelCoord"
returnVariable="convertMapCoordToPixelCoord" >
<cfinvokeargument name="mapCoord" type="" />
<cfinvokeargument name="viewExtent" type="" />
<cfinvokeargument name="mapImageSize" type="" />
</cfinvoke>
1345
The code that the Service Browser generates appears in the ColdFusion file. The following is an example of the code
that the Service Browser generates:
createObject("webservice",
"http://arcweb.esri.com/services/v2/MapImage.wsdl").convertMapCoordToPixelCoord(mapCoord,
viewExtent, mapImageSize);