A Database Access Agent that Uses Events

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: }

Figure 2 - DBAccessFailedEvent