title: When selecting row 0 in JTable the selection handler goes mad
body: <p>I'm having problems with the selection handler for a JTable. </p>
  
  <p>The table is updated every 15th second from a refresh thread in the Control.</p>
  
  <p>I want to select a row in my JTable and extract a column contents that I will use to build a filename from.</p>
  
  <p>As long as row 0 is not selected during a refresh everything works ok. But if row 0 is selected when the refresh is triggered it looks like it jumps between the setAppserverData procedure and the event handler until it exceeds the rowCount for the table and I get an IndexOutOfBoundsException.</p>
  
  <p>I'm a Java newbee and this is on the edge of my knowledge, so I'm having a hard time figuring out what is wrong with the code. My gut feeling is that it has something to do with me trying to achieve a MVC structure and I fail to separate the code in the correct way.</p>
  
  <p>// The controller</p>
  
  <pre><code>// Appserver worker
  class AppserverWorker extends SwingWorker&lt;Integer, Integer&gt;{
      protected Integer doInBackground() throws Exception{
  
          // Check appservers
          while(true){
              theModel.readAppservData();
  
              // Update action buttons
              try {
                  if(!theModel.isStatusOk()){
                      theGui.actionButtonPanel.setAppServBtnColor("RED");
                      //              theGui.actionButtonPanel.setButtonFlashOn();
                  }else theGui.actionButtonPanel.setAppServBtnColor("GREEN");
              } catch (IllegalArgumentException e1) {
                  sysLogger.logMsg("SEVERE",e1.getMessage());
                  JOptionPane.showMessageDialog(null, e1.getMessage());
              }
  
              // Update GUI
              theGui.extAppServPanel.setAppserverData(theModel.getAppservData());
  
              // Sleep refresh time
              // TODO read refresh from init table
              try {
                  Thread.sleep(appServRefreshTime);
              } catch (InterruptedException e) {}
          }
      }
  
  // List selection handler
  class SharedListSelectionHandler implements ListSelectionListener {
      public void valueChanged(ListSelectionEvent e) {
          if (!e.getValueIsAdjusting()){                  // To avoid double trigger of listener
              System.out.println("&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;");
              String fileName = null;
              String fileExt  = ".txt";
              ListSelectionModel lsm = (ListSelectionModel)e.getSource();
              try {       
                  int selectedRow = lsm.getAnchorSelectionIndex();                                // Get the row clicked
                  if (selectedRow&gt;=0){                                                            // If -1 no row selected
                      fileName = theGui.extAppServPanel.getAppservName(selectedRow)+fileExt;      // Get appserver name and build file name
                      theModel.readCollectFile(InitParameters.collectFilePath, fileName);         // Read collect file
                      theGui.extAppServPanel.setAppservInfo(theModel.getCollectFileContent());    // Fill the text panel with collect file
                  }
              }
              catch(FileNotFoundException e1){
                  sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": Collect file "+fileName+" is missing");
                  JOptionPane.showMessageDialog(null, "Collect file "+fileName+" is missing");
              }
  
              catch(IOException e1){
                  sysLogger.logMsg("SEVERE",this.getClass().getSimpleName()+": System error: An I/O error occurred");
                  System.err.println("System error: An I/O error occurred");
                  System.exit(0);;
              }
          }
      }
  }
  </code></pre>
  
  <p>// The view</p>
  
  <pre><code>public class ExtAppServPanel extends JPanel {
  
  private JTable table;
  private DefaultTableModel model;
  
  private JTextArea textAreaInfo;
  private JButton btnSaveInfo;
  private List colData;
  
  public boolean ignoreTableChanges = false;
  
  /**
   * Constructor
   */
  public ExtAppServPanel() {
      System.out.println(this.getClass().getSimpleName()+": Constructor");
  
      setLayout(new MigLayout("", "[350:376.00,grow,leading]", "[100px:100,grow][][48.00,grow][]"));
      this.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Application servers info", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0)));
  
      // Set up table
      String[] columnNames = {"Server name", "Type","Status"};
      model = new DefaultTableModel(null,columnNames);
      table = new  JTable(model){ 
  
          // Color code rows
          @Override
          public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
              Component comp = super.prepareRenderer(renderer, row, col);
  
              if (!isRowSelected(row)){
                  comp.setBackground(getBackground());
                  int modelRow = convertRowIndexToModel(row);
                  String type = (String)getModel().getValueAt(modelRow, 2);
                  if ("FAIL".equals(type)) comp.setBackground(Color.RED);
                  if ("WARNING".equals(type)) comp.setBackground(Color.YELLOW);
              }
              return comp;
          }
      };
  
      // Set grid
      table.setGridColor(Color.LIGHT_GRAY);
  
      // Set width and alignment
      table.getColumnModel().getColumn(1).setMinWidth(200);
      table.getColumnModel().getColumn(1).setMaxWidth(200);
      table.getColumnModel().getColumn(1).setPreferredWidth(200);
  
      table.getColumnModel().getColumn(2).setMinWidth(75);
      table.getColumnModel().getColumn(2).setMaxWidth(75);
      table.getColumnModel().getColumn(2).setPreferredWidth(75);
  
  
      // Add scrollpane
      JScrollPane scrollPane = new JScrollPane(table);
      scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
      scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
      table.setFillsViewportHeight(true);
      this.add(scrollPane, "cell 0 0,grow");
  
      // Set up text area
      JLabel lblDetails = new JLabel("Details");
      this.add(lblDetails, "cell 0 1,alignx leading");
  
      textAreaInfo = new JTextArea();
      textAreaInfo.setBackground(Color.BLACK);
      textAreaInfo.setForeground(Color.GREEN);
      textAreaInfo.setEditable(false);
      textAreaInfo.setFont(new Font("Lucida Console",Font.PLAIN,10));
  
      JScrollPane scrollPane_1 = new JScrollPane();
      scrollPane_1.setViewportView(textAreaInfo);
      this.add(scrollPane_1, "cell 0 2,grow");
  
      // Save button
      btnSaveInfo = new JButton("Save");
      add(btnSaveInfo, "cell 0 3,alignx right");
  }
  
  /*
   * Setters and getters
   */
  public void setAppserverData(ArrayList&lt;ArrayList&lt;String&gt;&gt; dataRecord) {
      ArrayList&lt;String&gt; dataCol = new ArrayList&lt;String&gt;();
  
      // Init values array from result set
      try {
          model.setRowCount(0);   // &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;  Problem
          String[] arrayRow;
          String status = "Ok";
  
          // Get first row from list
          dataCol = dataRecord.get(0);                    
          arrayRow = new String[dataCol.size()];  
          arrayRow[0] = dataCol.get(2);
          arrayRow[1] = dataCol.get(1);
          arrayRow[2] = dataCol.get(4);
  
          for (int i = 0; i &lt; dataRecord.size(); i++){
              dataCol = dataRecord.get(i);
  
              // Check status
              if (dataCol.get(4).toUpperCase().equals("FAIL")){
                  status = "FAIL";
              }else if (dataCol.get(4).toUpperCase().equals("WARNING")){
                  status = "WARNING";
              }
  
              if (!dataCol.get(2).toUpperCase().equals(arrayRow[0].toUpperCase())){   
                  arrayRow[2] = status;                           // Override status
                  System.out.println("&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;");
                  model.addRow(arrayRow);                         // Add row to table
                  arrayRow = new String[dataCol.size()];  
                  arrayRow[0] = dataCol.get(2);
                  arrayRow[1] = dataCol.get(1);
                  arrayRow[2] = dataCol.get(4);
                  status = "Ok";
              }
          }
          setAppservName();
      } catch (Exception e) {
          e.printStackTrace();
      }   
  }
  
  //  Get row count
  public int getRowCount(){   
      return model.getRowCount();
  }
  
  //  Set table data
  public void setAppservName(){   
      Vector data = model.getDataVector();
      Vector row = (Vector) data.elementAt(1);
  
      // Copy the first column
      int mColIndex = 0;-
      colData = new ArrayList(table.getRowCount()+1);
  
      for (int i = 0; i &lt; table.getRowCount(); i++) {
        row = (Vector) data.elementAt(i);
        colData.add(row.get(mColIndex));  
      }
  }
  
  //  Get table data
  public String getAppservName(int rowNum){   
      return (String) colData.get(rowNum);
  }
  
  // Set appserver info
  public void setAppservInfo(String appservInfo){
      textAreaInfo.setText(appservInfo);
      textAreaInfo.setCaretPosition(0);       // Set cursor at top of text
  }
  
  // Get appserver info
  public String getAppservInfo(){
      return textAreaInfo.getText();
  }
  
  /**
   * Action listeners
   */
  
  public void addTableRowListener(ListSelectionListener listSelectionEvent) {
      table.getSelectionModel().addListSelectionListener(listSelectionEvent);
  }
  
  public void addButtonListener(ActionListener buttonEvent) {
      btnSaveInfo.addActionListener(buttonEvent);
      btnSaveInfo.setActionCommand("saveAppServInfo");
  }
  </code></pre>
  
  <p>}</p>
  
  <p>Trace output when a non zero row is selected and the refresh thread is run</p>
  
  <pre><code>** Appserver worker **
  CmtModel: readAppservData
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;  Rowcount = 8
  </code></pre>
  
  <p>Trace output when the zero row is selected and the refresh thread is run</p>
  
  <pre><code>** Appserver worker **
  CmtModel: readAppservData
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 0 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 1 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 2 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 3 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 4 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 5 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 6 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 7 &lt;&lt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Updating the table &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;  Selection list handler ! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;
  &gt;&gt; Controll: selectedRow = 8 &lt;&lt;
  java.lang.IndexOutOfBoundsException: Index: 8, Size: 8
      at java.util.ArrayList.rangeCheck(Unknown Source)
      at java.util.ArrayList.get(Unknown Source)
      at panels.ExtAppServPanel.getAppservName(ExtAppServPanel.java:219)
      at Control$SharedListSelectionHandler.valueChanged(Control.java:330)
      at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
      at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
      at javax.swing.DefaultListSelectionModel.fireValueChanged(Unknown Source)
      at javax.swing.DefaultListSelectionModel.insertIndexInterval(Unknown Source)
      at javax.swing.JTable.tableRowsInserted(Unknown Source)
      at javax.swing.JTable.tableChanged(Unknown Source)
      at javax.swing.table.AbstractTableModel.fireTableChanged(Unknown Source)
      at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)
      at javax.swing.table.DefaultTableModel.insertRow(Unknown Source)
      at javax.swing.table.DefaultTableModel.addRow(Unknown Source)
      at javax.swing.table.DefaultTableModel.addRow(Unknown Source)
      at panels.ExtAppServPanel.setAppserverData(ExtAppServPanel.java:172)
      at Control$AppserverWorker.doInBackground(Control.java:434)
      at Control$AppserverWorker.doInBackground(Control.java:1)
      at javax.swing.SwingWorker$1.call(Unknown Source)
      at java.util.concurrent.FutureTask.run(Unknown Source)
      at javax.swing.SwingWorker.run(Unknown Source)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
      at java.lang.Thread.run(Unknown Source)
  </code></pre>