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:

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, Macromedia 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 MX 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 MX 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 MX 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 MX installer creates a mapping in the ColdFusion MX 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:

Note: You do not have to restart the event gateway instance when you make changes to a CFC. ColdFusion MX 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>

View comments in LiveDocs