Coverage Report - us.daveread.basicquery.queries.QueryHistory
 
Classes in this File Line Coverage Branch Coverage Complexity
QueryHistory
98%
61/62
100%
17/17
0
 
 1  
 package us.daveread.basicquery.queries;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.List;
 5  
 
 6  
 import org.apache.log4j.Logger;
 7  
 
 8  
 /**
 9  
  * Maintain the query history and current location in that history.
 10  
  * 
 11  
  * @author David Read
 12  
  */
 13  
 public class QueryHistory {
 14  
   /**
 15  
    * Logger
 16  
    */
 17  1
   private static final Logger LOGGER = Logger.getLogger(QueryHistory.class);
 18  
 
 19  
   /**
 20  
    * Maximum size of the query history list
 21  
    */
 22  
   private static final int MAXIMUM_HISTORY_ENTRIES = 1000;
 23  
 
 24  
   /**
 25  
    * Singleton instance
 26  
    */
 27  1
   private static QueryHistory instance = new QueryHistory();
 28  
 
 29  
   /**
 30  
    * Collection of historical queries
 31  
    */
 32  1
   private final List<QueryInfo> queryHistoryList = new ArrayList<QueryInfo>();
 33  
 
 34  
   /**
 35  
    * Current position in the history list
 36  
    */
 37  1
   private int currentPosition = -1;
 38  
 
 39  
   /**
 40  
    * Private constructor for Singleton
 41  
    */
 42  1
   private QueryHistory() {
 43  
 
 44  1
   }
 45  
 
 46  
   /**
 47  
    * Get the instance
 48  
    * 
 49  
    * @return The instance
 50  
    */
 51  
   public static final QueryHistory getInstance() {
 52  3077
     return instance;
 53  
   }
 54  
 
 55  
   /**
 56  
    * Places the query at end of list and changes current position to point to
 57  
    * that query. If the query is at the same position as the current query in
 58  
    * the history, then only the result set and connection URL are replaced.
 59  
    * 
 60  
    * 
 61  
    * @param query
 62  
    *          The query that is to be added to the history list
 63  
    */
 64  
   public void addQuery(QueryInfo query) {
 65  1033
     if (getNumberOfQueries() > 0
 66  
         && query.getSQLIndex() != getCurrentQueryInfo().getSQLIndex()) {
 67  1020
       truncateQueryHistory();
 68  
     }
 69  
 
 70  1033
     appendQuery(query);
 71  1033
   }
 72  
 
 73  
   /**
 74  
    * Delete the query at the SQL index position given. This is NOT the position
 75  
    * in the history list, it is the SQL index position. Any queries in the
 76  
    * history list with a matching SQL index will be removed and SQL indexes
 77  
    * beyond the removed index will be decremented by one so that they point to
 78  
    * the correct position in the SQL list.
 79  
    * 
 80  
    * @param index
 81  
    *          The SQL index of the query being deleted
 82  
    */
 83  
   public void deleteQueryAtIndex(int index) {
 84  1
     int position = 0;
 85  
     int histPosition;
 86  
 
 87  4
     while (position < queryHistoryList.size()) {
 88  3
       if (queryHistoryList.get(position).getSQLIndex() == index) {
 89  1
         queryHistoryList.remove(position);
 90  1
         if (getHistoryPosition() >= position) {
 91  1
           --currentPosition;
 92  
         }
 93  
       } else {
 94  2
         if ((histPosition = queryHistoryList.get(position).getSQLIndex()) > index) {
 95  1
           queryHistoryList.get(position).setSQLIndex(histPosition - 1);
 96  
         }
 97  
 
 98  2
         ++position;
 99  
       }
 100  
     }
 101  1
   }
 102  
 
 103  
   /**
 104  
    * Remove queries that follow the currently selected query in the history
 105  
    * list.
 106  
    */
 107  
   private void truncateQueryHistory() {
 108  1020
     if (getHistoryPosition() > -1) {
 109  1021
       while (queryHistoryList.size() > getHistoryPosition() + 1) {
 110  1
         LOGGER.debug("Removed item at=" + (getHistoryPosition() + 1));
 111  1
         queryHistoryList.remove(getHistoryPosition() + 1);
 112  
       }
 113  
     }
 114  
 
 115  1020
     LOGGER.debug("historyPosition=" + getHistoryPosition()
 116  
         + " historyQueries.size="
 117  
         + getNumberOfQueries());
 118  1020
   }
 119  
 
 120  
   /**
 121  
    * Append a query at the end of the history list. If the SQL index matches the
 122  
    * current history position's query's SQL index then only the results and
 123  
    * connection URL are updated in the query history.
 124  
    * 
 125  
    * @param query
 126  
    *          The query to be inserted at the end of the query history list
 127  
    */
 128  
   private void appendQuery(QueryInfo query) {
 129  1033
     if (getNumberOfQueries() == 0
 130  
         || query.getSQLIndex() != getCurrentQueryInfo().getSQLIndex()) {
 131  1032
       queryHistoryList.add(query);
 132  1032
       setHistoryPosition(getNumberOfQueries() - 1);
 133  1
     } else if (getNumberOfQueries() > 0
 134  
         && query.getSQLIndex() == getCurrentQueryInfo().getSQLIndex()) {
 135  1
       getCurrentQueryInfo().setResults(query.getResults());
 136  1
       getCurrentQueryInfo().setURLIndex(query.getURLIndex());
 137  
     }
 138  
 
 139  1033
     enforceSize();
 140  1033
   }
 141  
 
 142  
   /**
 143  
    * Ensure that the size of the history list does not go beyond the defined
 144  
    * maximum size
 145  
    */
 146  
   private void enforceSize() {
 147  1033
     if (queryHistoryList.size() > MAXIMUM_HISTORY_ENTRIES) {
 148  4
       while (queryHistoryList.size() > MAXIMUM_HISTORY_ENTRIES) {
 149  2
         queryHistoryList.remove(0);
 150  2
         --currentPosition;
 151  
       }
 152  
 
 153  
       /*
 154  
        * This "can't" happen, but is here in case there is a bug that allows the
 155  
        * history list to grow beyond the max size
 156  
        */
 157  2
       if (getHistoryPosition() < 0) {
 158  0
         currentPosition = 0;
 159  
       }
 160  
     }
 161  1033
   }
 162  
 
 163  
   /**
 164  
    * Set the current history position
 165  
    * 
 166  
    * @param position
 167  
    *          The current history position
 168  
    */
 169  
   private void setHistoryPosition(int position) {
 170  1032
     currentPosition = position;
 171  1032
   }
 172  
 
 173  
   /**
 174  
    * Get the number of queries in the history list
 175  
    * 
 176  
    * @return The number of queries in the history list
 177  
    */
 178  
   public int getNumberOfQueries() {
 179  4131
     return queryHistoryList.size();
 180  
   }
 181  
 
 182  
   /**
 183  
    * Get the position of the current query in the history list
 184  
    * 
 185  
    * @return The position of the current query in the history list
 186  
    */
 187  
   private int getHistoryPosition() {
 188  9186
     return currentPosition;
 189  
   }
 190  
 
 191  
   /**
 192  
    * Get the query info for the current query position in the history list. If
 193  
    * there is no query history and exception is thrown.
 194  
    * 
 195  
    * @return The current query info from the history list
 196  
    */
 197  
   public QueryInfo getCurrentQueryInfo() {
 198  2053
     if (getHistoryPosition() > -1) {
 199  2052
       return queryHistoryList.get(getHistoryPosition());
 200  
     } else {
 201  1
       throw new IllegalAccessError("No queries in the history list");
 202  
     }
 203  
   }
 204  
 
 205  
   /**
 206  
    * Move back one position in the history list. If the list is empty or already
 207  
    * at the beginning an exception is thrown
 208  
    * 
 209  
    * @see #hasPrevious()
 210  
    */
 211  
   public void moveBackward() {
 212  1008
     if (getHistoryPosition() > 0) {
 213  1007
       --currentPosition;
 214  
     } else {
 215  1
       throw new IllegalAccessError("No previous queries in the history list");
 216  
     }
 217  1007
   }
 218  
 
 219  
   /**
 220  
    * Move forward on position in the history list. If the list is empty of
 221  
    * already at the end an exception is thrown
 222  
    * 
 223  
    * @see #hasNext()
 224  
    */
 225  
   public void moveForward() {
 226  3
     if (getHistoryPosition() + 1 < getNumberOfQueries()) {
 227  2
       ++currentPosition;
 228  
     } else {
 229  1
       throw new IllegalAccessError("No more queries in the history list");
 230  
     }
 231  2
   }
 232  
 
 233  
   /**
 234  
    * Check whether there is a query in the history list prior to the current
 235  
    * history position.
 236  
    * 
 237  
    * @see #moveBackward()
 238  
    * 
 239  
    * @return True if there is a query prior to the current history position
 240  
    */
 241  
   public boolean hasPrevious() {
 242  1002
     return getHistoryPosition() > 0;
 243  
   }
 244  
 
 245  
   /**
 246  
    * Check whether there is a query in the history list after to the current
 247  
    * history position.
 248  
    * 
 249  
    * @see #moveForward()
 250  
    * 
 251  
    * @return True if there is a query after the current history position
 252  
    */
 253  
   public boolean hasNext() {
 254  2
     return getHistoryPosition() + 1 < getNumberOfQueries()
 255  
         && getNumberOfQueries() > 0;
 256  
   }
 257  
 
 258  
   /**
 259  
    * Remove all queries from history
 260  
    */
 261  
   public void clearAllQueries() {
 262  14
     queryHistoryList.clear();
 263  14
     currentPosition = -1;
 264  14
   }
 265  
 }