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:
Event gateway applications follow one or both of the following models:
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.
A ColdFusion application can send an outgoing message to the event gateway in either of the following ways:
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.
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.
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:
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 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.
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 installer creates a mapping in the ColdFusion Administrator for the gateway\cfc directory.
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.
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.
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:
<cfscript> sys = createObject("java", "java.lang.System"); sys.out.println("Debugging message goes here"); </cfscript>
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>
The SendGatewayMessage function has the following format:
SendGatewayMessage(gatewayID, messageStruct)
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>
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>
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.