A Database Query Agent

We will adapt our sample DBAccessProgram into a Concordia Agent called DBAccessAgent. The new agent will have the ability to travel to a database server, query the database, and then travel back to the user with the results of the query. Our agent will perform two tasks, each at a different location on the network. To accomplish this, the agent contains a method, named queryDatabase, to perform the database access, and a method, named reportResults, to report the results to the user.

At runtime, the queryDatabase method of the Agent executes on the database server and the reportResults method executes on the machine where the user is located. The code for the Agent is shown in Figure 2.


  1: /*  DBAccessAgent.java

  2:  *  Copyright © 1997 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: 

 13: import java.net.URL;

 14: import java.sql.*;

 15: import java.util.*;

 16: import java.io.*;

 17: 

 18: import COM.meitca.concordia.Agent;

 19: 

 20: /*

 21:  *  A Concordia Agent which tests the ability to access databases.

 22:  *  This agent travels to an Agent Manager and accesses an ODBC

 23:  *  database (via JDBC).  The information is then taken to

 24:  *  another Agent Manager where its results are reported to the

 25:  *  console.  This example accesses the "demo" database.

 26:  *  This example requires JDBC, ODBC and the JDBC-ODBC bridge.

 27:  *

 28:  */

 29: public class DBAccessAgent extends Agent {

 30:     /*

 31:      * This object contains the results of the SQL query made by the

 32:      * agent.

 33:      */

 34:     private QueryResult itsResult;

 35: 

 36:     /*

 37:      * This string specifies the sales region the agent is interested

 38:      * in.

 39:      */

 40:     private String itsRegion;

 41: 

 42:     /*

 43:      * Constructs a DBAccessAgent

 44:      */

 45:     public DBAccessAgent(String region) {

 46:         itsRegion = region;

 47:         itsResult = new QueryResult();

 48:     }

 49: 

 50:     /*

 51:      * Executes a SQL query on a database. This method performs  a

 52:      * simple SELECT query on an odbc database.  The results of the

 53:      * query are stuffed into a QueryResult object.

 54:      */

 55:     public void queryDatabase() {

 56: 

 57: 		try {

 58: 

 59:             // Load the JDBC-ODBC Bridge Driver

 60:     		Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

 61: 

 62:             // Create a URL specifying an ODBC data source name.

 63:             // This URL indicates an ODBC data source named demo.

 64:             String url = "jdbc:odbc:demo";

 65: 

 66:             // Connect to the database at that URL.

 67:             Connection con = DriverManager.getConnection(url);

 68: 

 69:             // Execute a SELECT statement

 70:             Statement stmt = con.createStatement();

 71:             ResultSet rs = stmt.executeQuery("SELECT DISTINCTROW Regions.Region, Sum([UnitPrice]*[Quantity]) AS Total " +

 72:                 "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 " +

 73:                 "GROUP BY Regions.Region " +

 74:                 "HAVING (((Regions.Region)='" + itsRegion + "')) " +

 75:                 "ORDER BY Regions.Region;");

 75: 

 76:             // Retrieve the result.

 77:             rs.next();

 78: 

 79:             //pull the results out of the Statement

 80:             itsResult.region = rs.getString(1);

 81:             itsResult.sales = rs.getFloat(2);

 82: 

 83:             stmt.close();

 84:             con.close();

 85:         } catch (java.lang.Exception ex) {

 86:             ex.printStackTrace();

 87:         }

 88:     }

 89: 

 90:     /*

 91:      * Report query results to console using System.out.println

 92:      * statements.  This method could also report the results

 93:      * using an AWT GUI, or had the results off to another

 94:      * Java class for manipulation or reporting.

 95:      */

 96:     public void reportResults() {

 97:         System.out.println("Sales for region " + itsResult.region + ":");

 98:         System.out.println("Sales = " + itsResult.sales);

 99:         System.out.print("\n");

100:

101:     }

102: }

 

Figure 2 - The Database Access Agent

The DBAccessAgent code is virtually identical to the DBAccessProgram code. However, this agent, and all Concordia Agents, derive from the base class COM.meitca.concordia.Agent (line 29). Between the time queryDatabase and reportResults actually execute, the agent travels across the network. In order to carry the results of the query back, they must be placed within a member variable of the agent. The itsResult member which holds the results of the query is simply a QueryResult object (line 34).

When an agent travels, its internal state including all member variables persists between locations. Any data that is to travel with the agent must be stored within its member variables. It is important to realize that there are some types of objects which cannot travel with the agent. For example, if an agent traveled to a machine, created a Java File object, and placed a reference to that object in one of its member variables, the reference would be invalid after the agent traveled from that machine. In general, objects that represent unique resources of a particular machine cannot travel with an agent. This includes things such as Files, Threads, Database Connections, Database Statements, Database ResultSets, and AWT components. Also, if one of an agent's member variables contains a reference to another agent, this reference would no longer be valid if either agent were to travel. In general, it is not a good idea to allow agents to contain references to other agents. The Concordia collaboration and distributed events frameworks provides more structured mechanism for allowing agents to interact.