Remember the DBAccessAgent presented earlier? It can easily be extended to use Concordia's distributed events. Figure 1 contains code for a database access agent that receives an event whenever the sales database has been updated. It also generates an event when it is unable to query the database.
1: /* DBAccessAgent.java 2: * Copyright © 1997-1998 Horizon Systems Laboratory, 3: * Mitsubishi Electric Information Technology Center America. 4: * All rights reserved. 5: * 6: * CONFIDENTIAL AND PROPRIETARY PROPERTY OF MITSUBISHI ELECTRIC ITA. 7: * 8: * DESCRIPTION 9: * A Concordia Agent which tests the ability to access databases. 10: * 11: */ 12: package examples.DeveloperGuide.events; 13: 14: import java.net.URL; 15: import java.sql.*; 16: import java.util.*; 17: import java.io.*; 18: import java.rmi.*; 19: 20: import COM.meitca.concordia.Agent; 21: import COM.meitca.concordia.event.*; 22: 23: /* 24: * A Concordia Agent which tests the ability to access databases. 25: * This agent travels to an Agent Manager and accesses an ODBC 26: * database (via JDBC). The information is then taken to 27: * another Agent Manager where its results are reported to the 28: * console. This example accesses the "demo" database. 29: * This example requires JDBC, ODBC and the JDBC-ODBC bridge. 30: * 31: */ 32: public class DBAccessAgent extends Agent { 33: 34: // This object contains the results of the SQL query made by the agent. 35: private QueryResult itsResult; 36: 37: // This string specifies the sales region the agent is interested in 38: private String itsRegion; 39: 40: /* 41: * Constructs an DBAccessAgent 42: */ 43: public DBAccessAgent(String region) 44: throws EventException { 45: 46: itsRegion = region; 47: itsResult = new QueryResult(); 48: 49: try { 50: // Create an asynchronous event handler. 51: makeEventHandler(false); 52: 53: // Make a direct connection to the Event Manager 54: makeEventManagerConnection(false); 55: 56: // Register to receive events 57: Class eventClass[] = {DBUpdateEvent.class}; 58: registerEvents(eventClass); 59: 60: } catch (Exception e) { 61: throw new EventException(e.toString() + e.getMessage()); 62: } 63: } 64: 65: 66: /* 67: * Executes a SQL query on a database. This method performs a 68: * simple SELECT query on an odbc database. The results of the 69: * query are stuffed into a QueryResult object. 70: */ 71: public void queryDatabase() { 72: 73: try { 74: 75: // Load the JDBC-ODBC Bridge Driver 76: Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 77: 78: // Create a URL specifying an ODBC data source name. 79: // This URL indicates an ODBC data source named demo. 80: String url = "jdbc:odbc:demo"; 81: 82: // Connect to the database at that URL. 83: Connection con = DriverManager.getConnection(url); 84: 85: // Execute a SELECT statement 86: Statement stmt = con.createStatement(); 87: ResultSet rs = stmt.executeQuery("SELECT DISTINCTROW Regions.Region, Sum([UnitPrice]*[Quantity]) AS Total " + 88: "FROM (Customers INNER JOIN (Orders INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID) ON Customers.CustomerID = Orders.CustomerID) INNER JOIN Regions ON Customers.Country = Regions.Country " + 89: "GROUP BY Regions.Region " + 90: "HAVING (((Regions.Region)='" + itsRegion + "')) " + 91: "ORDER BY Regions.Region;"); 92: 93: // Retrieve the result. 94: rs.next(); 95: 96: //pull the results out of the Statement 97: itsResult.region = rs.getString(1); 98: itsResult.sales = rs.getFloat(2); 99: 100: stmt.close(); 101: con.close(); 102: } catch (Exception ex) { 103: // Post a DBAcessFailedEvent. 104: try { 105: postEvent(new DBAccessFailedEvent(this, ex)); 106: } catch (Exception ex2) { 107: } 108: } 109: 110: synchronized(Thread.currentThread()) { 111: 112: try { 113: Thread.currentThread().wait(10000); 114: } catch (InterruptedException e) {} 115: } 116: 117: } 118: 119: 120: /* 121: * Report query results to console using System.out.println 122: * statements. This method could also report the results 123: * using an AWT GUI, or had the results off to another 124: * Java class for manipulation or reporting. 125: */ 126: public void reportResults() { 127: System.out.println("Sales for region " + itsResult.region + ":"); 128: System.out.println("Sales = " + itsResult.sales); 129: System.out.print("\n"); 130: } 131: 132: 133: /* 134: * The event handler. 125: */ 136: public void handleEvent(EventType event) 137: throws EventException { 138: 139: if (event instanceof DBUpdateEvent) { 140: System.out.println("Database has been updated"); 141: queryDatabase(); 142: } 143: } 144: 145: }
Figure 1 - A Database Access Agent Using Events
The agent first creates a asynchronous event handler (line 51). A synchronous event handler would be created by passing an argument of true to the makeEventHandler() method.
The agent then creates a direct connection to the Event Manager (line 54). If the agent, instead, wished to utilize a proxy (not available in the Freeware version of Concordia), it would pass a value of true to the makeEventManagerConnection() method.
The agent also registers to receive events of type DBUupdateEvent (line 58). The agent later handles events of that type by querying the database whenever it's been updated (lines 136-143). The agent also posts a DBAccessFailedEvent event whenever it fails to access the database (line 105). This event is shown in Figure 2. It is simply a specialization of AgentExceptionEvent that represents a failure to access a database.
1: import COM.meitca.concordia.AgentExceptionEvent; 2: 3: public class DBAccessFailedEvent extends AgentExceptionEvent { 4: 5: public DBAccessFailedEvent(Agent agent, Exception e) { 6: super(agent, e); 7: } 8: }