ColdFusion 9.0 Resources |
Building an event gatewayContents [Hide]To build a Gateway class, you can start with the EmptyGateway.java file as a template. (In the server configuration, this file is located in the cf_root/gateway/src/examples/ directory; in the J2EE configuration, the file is in the cf_root/WEB-INF/cfusion/gateway/src/examples/ directory.) This file defines a nonfunctional event gateway, but has the basic skeleton code for all Gateway class methods. Wherever possible, this document uses code based on the sample Socket event gateway to show how to implement event gateway features. (In the server configuration, this file is cf_root/gateway/src/examples/socket/SocketGateway.java; in the J2EE configuration, the file is cf_root/WEB-INF/cfusion/gateway/src/examples/socket/SocketGateway.java.) Class constructorAn event gateway can implement any of the following constructors:
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. 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); } Providing Gateway class service and information routinesSeveral gateway methods perform event gateway configuration services and provide event gateway information. The ColdFusion event gateway services call many of these methods to configure the event gateway by using information stored by the ColdFusion Administrator, and to get access to resources and information that the event gateway services and applications require. Some of these methods can also be useful in event gateway code. The following methods provide these services and information:
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; } Starting, stopping, and restarting the event gatewayBecause an event gateway uses at least one listener thread, it must have start, stop, and restart methods to control the threads. These methods must also maintain the status variable that the Gateway class getStatus method checks, and change its value among STARTING, RUNNING, STOPPING, STOPPED, and FAILED, as appropriate. The start methodThe start method initializes the event gateway. It starts one or more listener threads that monitor the event source and respond to any messages it receives from the source. 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. 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. 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; } The stop methodThe stop method performs the event gateway shutdown tasks, including shutting down the listener thread or threads and releasing any resources. The following example shows the SocketGateway stop method: public void stop() { // Set the status variable to indicate that the server is stopping. status = STOPPING; // The listening variable is used as a switch to stop listener activity. listening=false; // Close the listener thread sockets. Enumeration e = socketRegistry.elements(); while (e.hasMoreElements()) { try { ((SocketServerThread)e.nextElement()).socket.close(); } catch (IOException e1) { // We don't care if a close failed. //log.error(e1); } } // Close and release the serverSocket instance that gets requests from the // network. if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e1) { } //Release the serverSocket. serverSocket = null; } // Shutdown succeeded; set the status variable. status = STOPPED; } The restart methodIn most cases, you implement the restart method by calling the stop method and the start method consecutively, but you could be able to optimize this process for some services. The following code shows the SocketGateway class restart method: public void restart() { stop(); start(); } Responding to incoming messagesOne or more listener threads respond to incoming messages (events). The threads must include code to dispatch the messages to ColdFusion event gateway services, as follows:
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:
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.
private void processInput(String theInput, String theKey) { // Convert listeners list to a local array // Protect ourselves if the list changes while we are running String[] listeners; int size = cfcListeners.size(); if (size > 0) { // Capture the listeners list synchronized (cfcListeners) { listeners = new String[size]; cfcListeners.toArray(listeners); } } else { // Create a dummy list listeners = new String[1]; listeners[0] = null; } // Broadcast to all the CFC listeners // Send one message at a time with different CFC address on them for (int i = 0; i < listeners.length; i++) { String path = listeners[i]; CFEvent event = new CFEvent(gatewayID); Hashtable mydata = new Hashtable(); mydata.put("MESSAGE", theInput); event.setData(mydata); event.setGatewayType("SocketGateway"); event.setOriginatorID(theKey); event.setCfcMethod(cfcEntryPoint); event.setCfcTimeOut(10); if (path != null) event.setCfcPath(path); boolean sent = gatewayService.addEvent(event); if (!sent) log.error("SocketGateway(" + gatewayID + ") Unable to place message on event queue. Message not sent from " + gatewayID + ", thread " + theKey + ".Message was " + theInput); } } Responding to a ColdFusion function or listener CFCThe ColdFusion event gateway services call the outgoingMessage method of the gateway to handle messages generated when the listener method of an event gateway application listener CFC returns a message or any CFML code calls a SendGatewayMessage function. This method must send the message to the appropriate external resource. The outgoingMessage method parameter is a CFEvent instance, containing the information about the message to send out. The CFEvent getData method returns a Map object that contains event gateway-specific information about the message, including any message text. All CFEvent instances received by the outgoingMessage contain information in the Data and GatewayID fields. 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:
Example outgoingMessage methodThe following outgoingMessage method is like the version in the SocketGateway class. It does the following:
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; } Logging events and using log filesThe GatewayServices.getLogger method returns an instance of the coldfusion.eventgateway.Logger class that you can use to log messages to a file in the ColdFusion logs directory. (You set this directory on the ColdFusion Administrator Logging Settings page.) The method can take no parameter, or one parameter:
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.
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.
|