Class QueryAgent


  • public class QueryAgent
    extends java.lang.Object
    A class that is an agent for queries from the client environment to the server. All locked swing event dispatched JDBC queries should go through this class. These are queries where the user does something which results in a query being executed on the server, and must then wait for the result to be received.

    This class provides a mechanism which allows the client not to block indeffinately on the event dispatcher thread. This means we can give feedback to the user if a query is taking a long time (progress bar, hour-glass, etc) and components will repaint correctly. It also allows us to cancel any query in progress (because the event dispatcher isn't locked we can handle UI events and the interface won't be frozen).

    We acheive this behaviour with a hack of the system EventQueue (the same way modality works in swing.JInternalFrame). The low down is, we emulate the Java event dispatcher inner loop so that all AWT events (repaints/ component events/etc) are dispatched in our own controlled loop that is blocked with respect to the callee. (Find this blocking behaviour in SwingBlockUtil)

    I consider this a mild hack. This class may be incompatible with future versions of Java if the AWT event mechanism is altered. It may also not work happily with non-Sun based implementations of Java.

    NOTE: Other ways of acheiving non-AWT locking queries is with a delegate implementation. The method that executes the query returns immediately and the result is sent to a delegate. While this system sounds nice in theory, it's not pretty in practice. Especially if you need to execute many queries in a specific sequence. Also, handling exceptions is a nightmare with this idea.

    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      private class  QueryAgent.QueryThread
      The query thread.
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private SwingBlockUtil block_util
      The utility for blocking the swing event dispatch thread.
      private java.sql.Connection connection
      The JDBC Connection object for the connection to the database.
      private static QueryAgent query_agent  
      private char query_finished
      This represents the state of the result of the query.
      private QueryAgent.QueryThread query_thread
      The thread we use to send commands to the JDBC connection.
      private java.sql.ResultSet result_set
      If a ResultSet was obtained from the query, the ResultSet.
      private java.sql.SQLException sql_exception
      If an exception was thrown, the SQLException.
    • Constructor Summary

      Constructors 
      Constructor Description
      QueryAgent​(java.sql.Connection connection)
      Constructs the query agent.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static void cancel()
      Cancels the query that is currently being executed (if any).
      void cancelQuery()
      Cancels any query that is currently being executed by this agent.
      java.sql.Connection connection()
      Returns the connection for the JDBC interface.
      private java.awt.EventQueue eventQueue()
      Returns the current system EventQueue.
      static java.sql.ResultSet execute​(Query query)
      Executes a query on the default query agent for this VM.
      java.sql.ResultSet executeQuery​(Query query)
      Executes a query, blocking until a response from the server has been received.
      static QueryAgent getDefaultAgent()
      Returns the QueryAgent for this VM.
      static void initAgent​(java.sql.Connection connection)
      Initialises the QueryAgent with the given JDBC Connection.
      private boolean isQueryDone()
      Returns true if the query is done or not yet.
      private void notifyComplete​(java.sql.PreparedStatement statement, java.sql.ResultSet result_set)
      This is called when a query has finished and a valid ResultSet was returned as the result.
      private void notifyException​(java.sql.PreparedStatement statement, java.sql.SQLException e)
      This is called when a query has finished and an SQLException was thrown.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • connection

        private java.sql.Connection connection
        The JDBC Connection object for the connection to the database.
      • block_util

        private SwingBlockUtil block_util
        The utility for blocking the swing event dispatch thread.
      • query_thread

        private QueryAgent.QueryThread query_thread
        The thread we use to send commands to the JDBC connection.
      • query_finished

        private char query_finished
        This represents the state of the result of the query. Either 'n' (none), 'e' (exception), 'r' (result), 'f' (finished), or 'c' (cancelled).
      • sql_exception

        private java.sql.SQLException sql_exception
        If an exception was thrown, the SQLException.
      • result_set

        private java.sql.ResultSet result_set
        If a ResultSet was obtained from the query, the ResultSet.
      • query_agent

        private static QueryAgent query_agent
    • Constructor Detail

      • QueryAgent

        public QueryAgent​(java.sql.Connection connection)
        Constructs the query agent.
    • Method Detail

      • connection

        public java.sql.Connection connection()
        Returns the connection for the JDBC interface.
      • executeQuery

        public java.sql.ResultSet executeQuery​(Query query)
                                        throws java.sql.SQLException,
                                               java.lang.InterruptedException
        Executes a query, blocking until a response from the server has been received. This will send the command to the server on the QueryThread and emulates the event dispatch thread so AWT events can still be processed.

        This is based on the 'setModal' method found in JInternalFrame. It is up to the developer to block the user interface elements from being used while we are waiting for a query result.

        Throws an InterruptedException if the query is cancelled via the 'cancelQuery' method.

        Throws:
        java.sql.SQLException
        java.lang.InterruptedException
      • cancelQuery

        public void cancelQuery()
        Cancels any query that is currently being executed by this agent. This will cause the 'executeQuery' method to throw an InterruptedException.
      • eventQueue

        private java.awt.EventQueue eventQueue()
        Returns the current system EventQueue.
      • isQueryDone

        private boolean isQueryDone()
        Returns true if the query is done or not yet.
      • notifyException

        private void notifyException​(java.sql.PreparedStatement statement,
                                     java.sql.SQLException e)
        This is called when a query has finished and an SQLException was thrown.

        Called from the QueryThread.

      • notifyComplete

        private void notifyComplete​(java.sql.PreparedStatement statement,
                                    java.sql.ResultSet result_set)
        This is called when a query has finished and a valid ResultSet was returned as the result.

        Called from the QueryThread.

      • initAgent

        public static void initAgent​(java.sql.Connection connection)
        Initialises the QueryAgent with the given JDBC Connection.
      • getDefaultAgent

        public static QueryAgent getDefaultAgent()
        Returns the QueryAgent for this VM.
      • execute

        public static java.sql.ResultSet execute​(Query query)
                                          throws java.sql.SQLException,
                                                 java.lang.InterruptedException
        Executes a query on the default query agent for this VM. This must be called on the swing event dispatcher thread.

        This will block until the server has responded to the query and a result has been obtained. While this method does block, it still will service events on the event dispatcher queue. This means, UI elements will still work (buttons/text fields/etc) at the same time the server is fetching the result. And, we still have blocking behaviour for the callee.

        What this ultimately means, is that components can be repainted and we can have animations indicating the progress (feedback from the UI to the user that it hasn't frozen up) and buttons to cancel the query if it's taking too long.

        Throws:
        java.sql.SQLException
        java.lang.InterruptedException
      • cancel

        public static void cancel()
        Cancels the query that is currently being executed (if any). This must be called on the swing event dispatcher thread.

        This will throw an InterruptedException from the 'execute' method if it is waiting.