Package sample.dashboard

Source Code of sample.dashboard.GsaTableModel$ColumnProps

/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package sample.dashboard;

import com.google.enterprise.apis.client.GsaClient;
import com.google.enterprise.apis.client.GsaFeed;
import com.google.enterprise.apis.client.GsaEntry;
import com.google.enterprise.apis.client.Terms;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Map;
import javax.swing.table.AbstractTableModel;

/**
* Table model for the datagrid in DashMainForm.
*
* Normally, the table model for a data grid can be implemented as inner class of a swing form.
* However, this particular table model is complicated enough (e.g. it even has its own inner
* classes, accesses external servers, and has a self-updating thread) that it warrants being
* its own class.
*
*
*/
public class GsaTableModel extends AbstractTableModel {

  private static final long serialVersionUID = 1L;
  private static final int ROW_COUNT = 25;
  private static final Long ERROR_VALUE_LONG = new Long(-99999);
  private static final Double ERROR_VALUE_DOUBLE = new Double(-99999.9999);

  private static final Logger logger =
      Logger.getLogger(GsaTableModel.class.getName());

  private static final int HOST_COLUMN_INDEX = 0;
  private static final int SELECTION_BOX_COLUMN_INDEX = 1;
  private static final int CRAWL_STATUS_COLUMN_INDEX = 2;
  private static final int DOC_LIMIT_COLUMN_INDEX = 3;
  private static final int DOCS_FOUND_COLUMN_INDEX = 4;
  private static final int DOCS_SERVED_COLUMN_INDEX = 5;
  private static final int CRAWL_RATE_COLUMN_INDEX = 6;

  /** List of properties for each column, order as per the INDEX constants above */
  private static List<ColumnProps> columnPropList = new ArrayList<ColumnProps>() {
    {
      // column 0 properties: Host Name/IP Address
      add(new ColumnProps(null, null, null, String.class));
      // column 1 properties: Selection checkbox
      add(new ColumnProps(null, null, null, Boolean.class));
      // column 2 properties: Crawl status
      add(new ColumnProps(Terms.FEED_COMMAND,
                          Terms.ENTRY_PAUSE_CRAWL,
                          Terms.PROPERTY_PAUSE_CRAWL,
                          Boolean.class));
      // column 3 properties: Max URL
      add(new ColumnProps(Terms.FEED_CONFIG,
                          Terms.ENTRY_HOST_LOAD,
                          Terms.PROPERTY_MAX_URLS,
                          Long.class));
      // column 4 properties: URLs found
      add(new ColumnProps(Terms.FEED_STATUS,
                          Terms.ENTRY_DOCUMENT_STATUS,
                          Terms.PROPERTY_FOUND_URLS,
                          Long.class));
      // column 5 properties: URLs served
      add(new ColumnProps(Terms.FEED_STATUS,
                          Terms.ENTRY_DOCUMENT_STATUS,
                          Terms.PROPERTY_SERVED_URLS,
                          Long.class));
      // column 6 properties: Crawl rate
      add(new ColumnProps(Terms.FEED_STATUS,
                          Terms.ENTRY_DOCUMENT_STATUS,
                          Terms.PROPERTY_CRAWL_PAGES_PER_SECOND,
                          Double.class));
    }
  };

  /** Back-end data for the table model */
  private volatile List<RowData> rowDataList;

  /** Separate the column headers (UI), from the rest of the column properties (data) */
  private List<String> columnHeaderList;

  /**
   * Constructs a table model, which also starts the thread to periodically
   * refresh the data stored in the model.
   */
  public GsaTableModel() {
    rowDataList = new ArrayList<RowData>();
    logger.info("Number of columns: " + String.valueOf(columnPropList.size()));
    columnHeaderList = new ArrayList<String>(columnPropList.size());
    for (int i = 0; i < columnPropList.size(); i++) {
      columnHeaderList.add(null);
    }
    logger.info("Size of Created header list: " + String.valueOf(columnHeaderList.size()));
  }

  @Override
  public int getRowCount() {
    return ROW_COUNT;
  }

  @Override
  public int getColumnCount() {
    return columnPropList.size();
  }

  /**
   * Sets the column header title.
   *
   * @param col 0-based column index for which to set title
   * @param value column title to set
   */
  public void setColumnName(int col, String value) {
    columnHeaderList.set(col, value);
  }

  @Override
  public String getColumnName(int col) {
    return columnHeaderList.get(col);
  }

  /**
   * Overrides the TableModel getter used to paint the grid.
   *
   * Columns 2, 3, 4, 5, 6 are the data retrieved from the GSA using GData API calls,
   * while column 0, although stored as a GsaClient in the data model, is returned
   * as the hostname/address used when creating the GsaClient.
   * Column 1 is the user selection box input, and therefore is not read from the GSA.
   *
   * @param row the row index of the value to retrieve
   * @param col the column index of the value to retrieve
   * @return a generic object representing/wrapping the value stored in the model
   */
  @Override
  public Object getValueAt(int row, int col) {
    if ((row < 0) || (row >= rowDataList.size())) {
      return null;
    }
    RowData rowData = rowDataList.get(row);
    if (rowData == null) {
      throw new NullPointerException();
    }
    switch (col) {
      case HOST_COLUMN_INDEX:
        if (rowData.client == null) {
          throw new NullPointerException();
        }
        return rowData.client.getAddress();
      case SELECTION_BOX_COLUMN_INDEX:
        return rowData.isSelected;
      case CRAWL_STATUS_COLUMN_INDEX:
        return rowData.isPaused;
      case DOC_LIMIT_COLUMN_INDEX:
        return rowData.docLimit;
      case DOCS_FOUND_COLUMN_INDEX:
        return rowData.docsFound;
      case DOCS_SERVED_COLUMN_INDEX:
        return rowData.docsServed;
      case CRAWL_RATE_COLUMN_INDEX:
        return rowData.crawlRate;
      default:
        return null;
    }
  }
 
  /**
   * Overrides the getter to fetch the object class for each column data type,
   * in order for the grid renderer to function properly.
   */
  @Override
  public Class<?> getColumnClass(int col) {
    return columnPropList.get(col).colClass;
  }

  /**
   * Used by the control to lock specific cells, rows, or column of the grid.
   *
   * Only the second (selection box) columns of the data is editable by the user/GUI.
   */
  @Override
  public boolean isCellEditable(int row, int col) {
    // column 1 can be edited to select the GSA you want to modify
    return (col == SELECTION_BOX_COLUMN_INDEX);
  }

  /**
   * Overrides the setter that updates the data stored in the datamodel,
   * based on changes happening in the GUI.
   *
   * Note that we only allow value updates for data in column 1 (an unbound selection box).
   */
  @Override
  public void setValueAt(Object value, int row, int col) {
    if (value == null) {
      throw new NullPointerException();
    }
    // only set the selection flag if this row has a GSA client
    if (col == SELECTION_BOX_COLUMN_INDEX && row < rowDataList.size()) {
        rowDataList.get(row).isSelected = (Boolean) value;
        fireTableRowsUpdated(row, row);
    }
  }

  /**
   * Adds new GSA server.
   * @param client the GsaClient connecting to the GSA server
   */
  public void addServer(GsaClient client) {
    // move it to after the last row with data in it
    rowDataList.add(new RowData(client));
    int row = rowDataList.size() - 1;
    logger.info("Row " + String.valueOf(row) + " updated");
    // since there will be latency in GData call, refresh the hostname/address first
    fireTableRowsUpdated(row, row);
  }

  /**
   * Returns the total number of servers
   * @return the total number of servers
   */
  public int countServer() {
    return rowDataList.size();
  }

  /**
   * Gets the GsaClient corresponding to the row
   * @param row the row number of GsaClient
   * @return the GsaClient connecting to the GSA server
   */
  public GsaClient getServer(int row) {
    if (row >= 0 && row < rowDataList.size()) {
      return rowDataList.get(row).client;
    } else {
      return null;
    }
  }

  /**
   * Returns a list of GsaClients with its corresponding selection box clicked.
   *
   * @return a collection of GsaClients, with their "Selected" status set to true
   */
  public List<GsaClient> getSelectedClients() {
    List<GsaClient> returnVal = new ArrayList<GsaClient>();
   
    for (RowData rowData : rowDataList) {
      if ((rowData.isSelected != null) && rowData.isSelected) {
        returnVal.add(rowData.client);
      }
    }
    return returnVal;
  }
 
  /**
   * Removes selected GSAs from monitoring.
   */
  public void removeRows() {
    for (Iterator<RowData> i = rowDataList.iterator(); i.hasNext(); ) {
      RowData rowData = i.next();
      if ((rowData.isSelected != null) && rowData.isSelected) {
        rowData.finished = true;
        i.remove();
      }
    }
    fireTableDataChanged();
  }

  /**
   * Sets or clears all selection boxes on rows with GsaClients entered.
   *
   * @param status true to set all selection boxes, false to clear all selection boxes
   */
  public void selectAllRows(boolean status) {
    for (RowData rowData : rowDataList) {
     
      // Boolean class is anticipated by the grid
      rowData.isSelected = Boolean.valueOf(status);
    }
    fireTableDataChanged();
  }

  /**
   * Sets all values inside the input row data to the error value, a large negative scalar.
   * 
   * @param rowData row data class to set to error value
   */
  public void setToErrorValues(RowData rowData) {
    rowData.docLimit = ERROR_VALUE_LONG;
    rowData.docsFound = ERROR_VALUE_LONG;
    rowData.docsServed = ERROR_VALUE_LONG;
    rowData.crawlRate = ERROR_VALUE_DOUBLE;
  }

  /**
   * Retrieves all relevant values, based on ColumnProperties defined, from a GsaClient.
   *
   * @param rowData row data class whose data to update
   */
  public void refreshRow(RowData rowData) {
    /*
     * Implementation Note:
     * In order to avoid repeated GData calls to the GSA, which is the most expensive operation
     * in this function, the function attempts to cache the queried feeds in a map.
     * The entries in each feed were also themselves stored in a maps after the GData call,
     * in order to speed up subsequent refresh logic. 
     */
    Map<String, Map<String, GsaEntry>> feedMap = new HashMap<String, Map<String, GsaEntry>>();
    GsaClient client = rowData.client;

    try {
      for (int i = 0; i < columnPropList.size(); i++) {

        // do not refresh hostname column or the selection box column
        if ((i == HOST_COLUMN_INDEX) || (i == SELECTION_BOX_COLUMN_INDEX))
          continue;

        ColumnProps colProps = columnPropList.get(i);
        if ((colProps.feedName == null) || (colProps.entryId == null)) {
          continue;
        }

        if (!feedMap.containsKey(colProps.feedName)) {
          // Create another set in the map.
          GsaFeed feed = null;
          feed = client.getFeed(colProps.feedName);
          Map<String, GsaEntry> entryMap = new HashMap<String, GsaEntry>();
          for (GsaEntry entry : feed.getEntries()) {
            String entryID = entry.getGsaContent("entryID");
            entryMap.put(entryID, entry);
          }
          feedMap.put(colProps.feedName, entryMap);
        }

        String value = null;
        if (feedMap.containsKey(colProps.feedName)) {
          Map<String, GsaEntry> entryMap = feedMap.get(colProps.feedName);
          if (entryMap.containsKey(colProps.entryId)) {
            value = entryMap.get(colProps.entryId).getGsaContent(colProps.contentName);
          }
        }

        switch (i) {
          case CRAWL_STATUS_COLUMN_INDEX:
            rowData.isPaused = (value == null) ? null : (Integer.parseInt(value) != 0);
            break;
          case DOC_LIMIT_COLUMN_INDEX:
            rowData.docLimit = (value == null) ? null :
                (value.equals("") ? new Long(0) : new Long(value.replace(",", "")));
            break;
          case DOCS_FOUND_COLUMN_INDEX:
            rowData.docsFound = (value == null) ? null : new Long(value.replace(",", ""));
            break;
          case DOCS_SERVED_COLUMN_INDEX:
            rowData.docsServed = (value == null) ? null : new Long(value.replace(",", ""));
            break;
          case CRAWL_RATE_COLUMN_INDEX:
            rowData.crawlRate = (value == null) ? null : new Double(value.replace(",", ""));
            break;
        }
      }
    } catch (Exception ex) {
      /*
       * Note since this is a GUI refresh, to be invoked periodically by a thread
       * running in the background, throwing exception and causing termination of the thread
       * is not a good option.  Instead, when exceptions are encountered, all values in
       * the row being refreshed will be set to a large negative value.
       *
       * The usage of the generic Exception class is also intentional, since the various possible
       * exceptions in this method are to be treated the same way, which is:
       * (1) log it, (2) set this row to large negative error values, (3) refresh the GUI.
       */
      logger.log(Level.SEVERE, ex.getMessage());
      setToErrorValues(rowData);
    } finally {
      fireTableDataChanged();
    }
  }

  /**
   * Retrieves all relevant values, based on ColumnProperties defined, from a GsaClient.
   *
   * @param row the index of the row whose data to update
   */
  public void refreshRow(int row) {
    RowData rowData = rowDataList.get(row);
    refreshRow(rowData);
  }

  /**
   * private inner class used as data element aggregator.
   */
  private class RowData extends Thread {
    public GsaClient client;
    public Boolean isSelected;
    public Boolean isPaused;
    public Long docLimit;
    public Long docsFound;
    public Long docsServed;
    public Double crawlRate;
    public Boolean finished;
   
    public RowData(GsaClient client) {
      this.client = client;
      this.finished = false;
      this.start();
    }

    @Override
    public void run() {
      super.run();
      while(!finished) {
          logger.info("Refreshing client: " + client.getAddress());
          refreshRow(this);
        try {
          // sleep for 3 second
          sleep(3000);
        } catch (InterruptedException ex) {
          // Do nothing while being interrupted
          logger.severe(ex.toString());
        }
      }
    }
   
  }

  /**
   * private inner class used as column attribute aggregator.
   */
  private static class ColumnProps {
    public String feedName;
    public String entryId;
    public String contentName;
    public Class<?> colClass;
   
    public ColumnProps(String feedName, String entryId, String contentName, Class<?> columnClass) {
      this.feedName = feedName;
      this.entryId = entryId;
      this.contentName = contentName;
      this.colClass = columnClass;
    }
  }
 
}
TOP

Related Classes of sample.dashboard.GsaTableModel$ColumnProps

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.