Adobe ColdFusion 8

Developing an event gateway application

All event gateway applications handle information. They exchange event messages, and possibly other types of information, with other resources. Event gateway applications require a listener CFC to handle events that are sent to the event gateway. Event gateway applications can also use the following code elements:

  • SendGatewayMessage CFML functions to send messages from outside the listener CFC (or, optionally, from the CFC)
  • GatewayHelper objects
  • The eventgateway log file

Event gateway application models

Event gateway applications follow one or both of the following models:

  • Responder applications: Where event messages from external sources initiate a response from a ColdFusion listener CFC
  • Initiator applications: Where a ColdFusion application generates event messages to send out using the event gateway

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 similar to most ColdFusion applications. At some point, ColdFusion executes a CFM page in response to a request. (The request could be initiated by the ColdFusion Administrator Scheduled Tasks page.) 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.

Sending information to the event gateway

A ColdFusion application can send an outgoing message to the event gateway in either of the following ways:

  • In a cfreturn tag in the listener CFC's listener method
  • By calling the ColdFusion SendGatewayMessage function

The first method is useful to automatically respond to incoming messages. Some complex applications that respond to incoming messages might use the SendGatewayMessage function either in place or in addition to the return value.

Some event gateway types also use a GatewayHelper object to send information to external resources. For example, the ColdFusion XMPP and Lotus Sametime instant messaging event gateways provide a GatewayHelper object that can manage buddy lists, and set configuration and status information on the instant messaging server. For more information on the GatewayHelper object, see Using the GatewayHelper object. For more information on the instant messaging GatewayHelper object, see Sample IM message handling application.

The example code in Example event gateway CFC shows the use of a listener return value, and indicates how event gateways can require different data in the return structure to send equivalent messages.

Developing event gateway listener CFCs

The listener CFC responds to event gateway messages. The listener CFC uses, at a minimum, the following basic software elements:

  • One or more listener methods
  • CFEvent structures that contain the messages

Listener CFCs can use ColdFusion persistent scopes to store data that needs to be preserved over multiple CFC invocations or shared with other CFML elements.

Listener methods

The ColdFusion event gateway service calls one or more listener methods in the CFC to process incoming messages. The number of listener methods that you must write and their names depends on the event gateway. For example, the ColdFusion SMS event gateway requires a single listener method, which is typically named onIncomingMessage. (You can change the SMS event gateway listener method name in the event gateway configuration file.) The ColdFusion XMPP IM event gateway expects the listener CFC to have five methods: onIncomingMessage, onAddBuddyRequest, onAddBuddyResponse, onBuddyStatus, and onIMServerMessage. By default, if the event gateway does not specify the method name, ColdFusion calls the listener CFC's onIncomingMessage method. For the sake of consistency, Adobe recommends that any event gateway with a single listener method use the onIncomingMessage method.

The listener method does the following:

  1. Takes a single parameter, a CFEvent structure, described in the following section.
  2. Processes the contents of the instance as required by the application.
  3. Optionally, returns an outgoing message to the event gateway in a cfreturn tag. It can also send a message back to the event gateway by calling the ColdFusion SendGatewayMessage function.

The following code shows a listener CFC with an onIncomingMessage method that echoes a message back to the Socket event gateway that sent it. It contains the minimum code required to process an incoming message and respond to the sender using the socket gateway.

<cfcomponent displayname="echo" hint="echo messages from the event gateway">
    <cffunction name="onIncomingMessage" output="no">
        <cfargument name="CFEvent" type="struct" required="yes">
        <!--- Create a return structure that contains the message. --->
        <cfset retValue = structNew()>
        <cfset retValue.DestinationID = arguments.CFEvent.OriginatorID>
        <cfset retValue.MESSAGE = "Echo: " & arguments.CFEvent.Data.MESSAGE>
        <!--- Send the return message back. --->
        <cfreturn retValue>
    </cffunction>
</cfcomponent>

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 retValue.command = "submit">
<cfset retValue.sourceAddress = arguments.CFEVENT.gatewayid>
<cfset retValue.destAddress = arguments.CFEVENT.originatorid>
<cfset retValue.ShortMessage = "Echo: " & arguments.CFEvent.Data.MESSAGE>

The CFEvent structure

The ColdFusion event gateway service passes a CFEvent structure with information about the message event to the listener method. The following table describes the structure's fields:

Field

Description

GatewayID

The event gateway that sent the event; the value is the ID of an event gateway instance configured on the ColdFusion Administrator Gateways page. If the application calls the SendGatewayMessage function to respond to the event gateway, it uses this ID as the function's 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 is specified by the event Gateway class. 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 need to use this field.

CFCMethod

The listener method that ColdFusion invokes to process the event. The listener CFC does not need to use this field.

CFCTimeout

The time-out, in seconds, for the listener CFC to process the event request. The listener CFC does not need to use 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 event gateway's outgoingMessage method.

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:

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 might be used to send messages. Also, you can put 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:

  • the ColdFusion web root
  • a directory that is in the ColdFusion Administrator Mappings list.

The ColdFusion installer creates a mapping in the ColdFusion Administrator for the gateway\cfc directory.

Client scope

The Client scope can store long-term information associated with a message sender's ID. For example, it can store information about an IM buddy.

To use Client variables across multiple connections, your gateway type must use the same client ID for all interactions with a particular client. For many technologies and gateways, such as the IM and SMS gateways, this is not an issue.

Note: To use Client scope variables with gateways, you must store the Client scope variables in a data source or the registry. You cannot store the variables in cookies, because gateways do not use cookies.

Session scope

The Session scope can store information required across multiple interactions. For example, an interactive IM or SMS application that uses a drill-down menu to select a service can store the information about the menu selections in the Session scope.

Event gateway sessions terminate when they time out. Because the identifiers for event sessions and clients differ from those used for request-driven sessions and clients, you cannot use the same Session or Client scope on a standard CFM page that sends an outgoing message and in a listener CFC that might handle an incoming response to that message.

For an example of using the Session scope, see the example Menu application in the gateway\cfc\examples\menu directory.

Note: ColdFusion cannot create a session if an initiator application uses a SendGatewayMessage method to start an interaction with a client, such as an SMS user. In this case, the sending code must keep track (for example, in a database) of the messages it sends and their destinations. When a response event arrives, it can look up the origniatorID to determine whether it was in response to an outgoing message.

Debugging event gateway CFCs

When an event gateway CFC responds to an event, it cannot display debugging information in the response page, as CFM pages do. As a result, many of the normal ColdFusion debugging techniques, including the cfdump tag, are not available. When you develop event gateway CFCs, you should consider the following debugging techniques:

  • Put trace variables in the Application scope. These variables persist, and you can specify an application name for your CFC (see Application scope). 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.
  • You can simulate responses from CFCs to the event gateway by using the SendGatewayMessage function in a CFM page. The function's message parameter should contain the information that the CFC would put 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 make changes to 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
                (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>

Sending a message using the SendGatewayMessage function

The SendGatewayMessage function has the following format:

SendGatewayMessage(gatewayID, messageStruct)

  • The gatewayID parameter must be the gateway ID specified in the ColdFusion Administrator for the event gateway instance that will send the message.
  • The messageStruct parameter is a structure whose contents depends on the requirements of the event gateway's outgoingMessage method, and possibly the recipient application. For example, in addition to any message, the structure might 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.

Using the GatewayHelper object

The ColdFusion GetGatewayHelper function tells ColdFusion to create and initialize a Java GatewayHelper object that provides event gateway-specific helper methods and properties. To use this function, the event gateway must implement a GatewayHelper class. For example, an instant messaging event gateway might make buddy list management methods available in a GatewayHelper object.

The ColdFusion GetGatewayHelper function takes a single parameter, the ID of the event gateway instance that provides the helper, and returns a GatewayHelper Java object. The parameter value must be the gateway ID for the instance that is specified in the ColdFusion Administrator. If you do not want to hard-code an ID value in the application (for example, if your listener CFC can respond to multiple event gateway instances), get the gateway ID from the CFEvent structure of the first incoming message.

The CFML code accesses the GatewayHelper object's methods and properties using standard ColdFusion Java object access techniques (see Integrating J2EE and Java Elements in CFML Applications). For example, if an event gateway's GatewayHelper class includes an addBuddy method that takes a single String parameter, you could use the following code to get the ColdFusion XMPP or Sametime gateway GatewayHelper object and add a buddy to the buddies list:

<cfscript>
    myHelper = GetGatewayHelper(myGatewayID);
    status = myHelper.addBuddy("jsmith23", "Jim Smith", "support");
</cfscript>

Using the event gateway error log file

When a standard ColdFusion event gateway encounters an error that does not prevent the event gateway from continuing to process, it logs it to the eventgateway.log file in the ColdFusion logs directory. Other event gateways can also to log information in this file, or to other application-specific files in the logs directory.

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.