@Override
  protected Void doInBackground() throws Exception {
    // protein identification id
    Collection<Comparable> protIdentIds = controller.getIdentificationIds();

    // protein identification id and accession buffer
    Map<Comparable, String> accBuffer = new LinkedHashMap<Comparable, String>();

    // protein map
    Map<String, Protein> proteins = new HashMap<String, Protein>();

    try {
      // iterate over each protein
      for (Comparable protIdentId : protIdentIds) {
        // get mapped protein accession
        String protAcc = controller.getProteinAccession(protIdentId);
        String protAccVersion = controller.getProteinAccessionVersion(protIdentId);
        String database = controller.getSearchDatabase(protIdentId);
        AccessionResolver resolver = new AccessionResolver(protAcc, protAccVersion, database, true);
        String mappedProtAcc = resolver.isValidAccession() ? resolver.getAccession() : null;

        if (mappedProtAcc != null) {
          // get existing protein details
          Protein protDetails =
              PrideInspectorCacheManager.getInstance().getProteinDetails(mappedProtAcc);
          if (protDetails != null) {
            proteins.put(mappedProtAcc, protDetails);
          }

          accBuffer.put(protIdentId, mappedProtAcc);
          if (accBuffer.size() == MAX_BATCH_DOWNLOAD_SIZE) {
            // fetch and publish protein details
            fetchAndPublish(accBuffer, proteins);

            // clear accession buffer
            accBuffer.clear();

            // clear protein map
            proteins = new HashMap<String, Protein>();
          }
        }
      }

      // this is important for cancelling
      if (Thread.interrupted()) {
        throw new InterruptedException();
      }

      if (!accBuffer.isEmpty() || !proteins.isEmpty()) {
        fetchAndPublish(accBuffer, proteins);
      }
    } catch (InterruptedException e) {
      logger.warn("Protein name download has been cancelled");
    }

    return null;
  }
  public synchronized void removeDataAccessController(DataAccessController controller) {
    List<DataAccessController> oldControllers, newControllers;

    int index = controllers.indexOf(controller);
    if (index >= 0) {
      oldControllers = new ArrayList<DataAccessController>(controllers);
      // get the next available controller's index
      int nextIndex = controllers.size() - 1 > index ? index : index - 1;
      controllers.remove(controller);
      if (foregroundController != null && foregroundController.equals(controller)) {
        setForegroundDataAccessController(nextIndex >= 0 ? controllers.get(nextIndex) : null);
      }
      controller.close();
      newControllers = new ArrayList<DataAccessController>(controllers);

      EventBus.publish(
          new RemoveDataSourceEvent<DataAccessController>(this, oldControllers, newControllers));
    }
  }
  /**
   * Replace one data access controller with another, and retain the position in the
   * DataAccessMonitor.
   *
   * @param original original data access controller
   * @param replacement replacement data access controller
   */
  public synchronized void replaceDataAccessController(
      DataAccessController original, DataAccessController replacement) {
    List<DataAccessController> oldControllers, newControllers;

    int index = controllers.indexOf(original);
    if (index >= 0) {
      oldControllers = new ArrayList<DataAccessController>(controllers);
      controllers.add(index, replacement);
      controllers.remove(original);
      if (foregroundController != null && foregroundController.equals(original)) {
        setForegroundDataAccessController(replacement);
      }
      original.close();
      newControllers = new ArrayList<DataAccessController>(controllers);
      // notify others
      EventBus.publish(
          new AddDataSourceEvent<DataAccessController>(this, oldControllers, newControllers));
    } else {
      // add as a new data access controller
      addDataAccessController(replacement);
    }
  }
 private void updateComponents() {
   try {
     this.removeAll();
     if (controller != null) {
       Collection<Comparable> expIds = controller.getExperimentAccs();
       if (expIds == null || expIds.isEmpty()) {
         this.add(dataSourceTabPane, BorderLayout.CENTER);
       } else {
         JSplitPane splitPane =
             new JSplitPane(JSplitPane.VERTICAL_SPLIT, dataSourceTabPane, expTreeTabPane);
         splitPane.setOneTouchExpandable(false);
         splitPane.setDividerSize(0);
         splitPane.setResizeWeight(0.3);
         this.add(splitPane, BorderLayout.CENTER);
       }
     }
     this.revalidate();
     this.repaint();
   } catch (DataAccessException e) {
     e.printStackTrace(); // To change body of catch statement use File | Settings | File
     // Templates.
   }
 }
  /**
   * Fetch then publish
   *
   * @param accs protein accessions
   * @param proteins protein map
   * @throws Exception exception while fetching the protein
   */
  private void fetchAndPublish(Map<Comparable, String> accs, Map<String, Protein> proteins)
      throws Exception {
    Collection<String> accsToFetch = new HashSet<String>(accs.values());
    accsToFetch.removeAll(proteins.keySet());
    // fetch protein details
    Map<String, Protein> results = fetcher.getProteinDetails(accsToFetch);
    // add results to cache
    PrideInspectorCacheManager.getInstance().addProteinDetails(results.values());
    // add results to protein map
    proteins.putAll(results);
    // public results
    publish(new Tuple<TableContentType, Object>(TableContentType.PROTEIN_DETAILS, proteins));

    // protein sequence coverage
    Map<Comparable, Double> coverageMap = new HashMap<Comparable, Double>();
    // peptide fits
    Map<Tuple<Comparable, Comparable>, Integer> peptideFits =
        new HashMap<Tuple<Comparable, Comparable>, Integer>();

    for (Comparable protIdentId : accs.keySet()) {
      // protein sequence coverage
      Double coverage =
          PrideInspectorCacheManager.getInstance()
              .getSequenceCoverage(controller.getUid(), protIdentId);
      if (coverage == null) {
        String mappedProtAcc = accs.get(protIdentId);

        // get protein details
        Protein protein = proteins.get(mappedProtAcc);
        if (protein != null) {
          AnnotatedProtein annotatedProtein = new AnnotatedProtein(protein);
          Collection<Comparable> peptideIds = controller.getPeptideIds(protIdentId);
          for (Comparable peptideId : peptideIds) {
            PeptideAnnotation peptide = new PeptideAnnotation();
            peptide.setSequence(controller.getPeptideSequence(protIdentId, peptideId));
            peptide.setStart(controller.getPeptideSequenceStart(protIdentId, peptideId));
            peptide.setEnd(controller.getPeptideSequenceEnd(protIdentId, peptideId));
            annotatedProtein.addAnnotation(peptide);
          }
          coverage = annotatedProtein.getSequenceCoverage();
          coverageMap.put(protIdentId, coverage);
          // cache the sequence coverage
          PrideInspectorCacheManager.getInstance()
              .addSequenceCoverage(controller.getUid(), protIdentId, coverage);
        }
      } else {
        coverageMap.put(protIdentId, coverage);
      }

      // peptide fits
      Collection<Comparable> peptideIdentIds = controller.getPeptideIds(protIdentId);
      for (Comparable peptideIdentId : peptideIdentIds) {
        Integer state =
            PrideInspectorCacheManager.getInstance()
                .getPeptideFitState(controller.getUid(), protIdentId, peptideIdentId);
        if (state == null) {
          String mappedProtAcc = accs.get(protIdentId);

          // get protein details
          Protein protein = proteins.get(mappedProtAcc);
          if (protein != null) {
            protein = new AnnotatedProtein(protein);
          }

          // get peptide sequence
          String sequence = controller.getPeptideSequence(protIdentId, peptideIdentId);

          // start and end position
          int start = controller.getPeptideSequenceStart(protIdentId, peptideIdentId);
          int end = controller.getPeptideSequenceEnd(protIdentId, peptideIdentId);

          // peptide present
          if (protein == null || sequence == null || protein.getSequenceString() == null) {
            state = PeptideFitState.UNKNOWN;
          } else {
            if (protein.hasSubSequenceString(sequence, start, end)) {
              state = PeptideFitState.STRICT_FIT;
            } else if (protein.hasSubSequenceString(sequence)) {
              state = PeptideFitState.FIT;
            } else {
              state = PeptideFitState.NOT_FIT;
            }
          }
          PrideInspectorCacheManager.getInstance()
              .addPeptideFitState(controller.getUid(), protIdentId, peptideIdentId, state);
        }
        peptideFits.put(new Tuple<Comparable, Comparable>(protIdentId, peptideIdentId), state);
      }
    }

    // publish sequence coverage results
    publish(
        new Tuple<TableContentType, Object>(
            TableContentType.PROTEIN_SEQUENCE_COVERAGE, coverageMap));

    // publish peptide fit result
    publish(new Tuple<TableContentType, Object>(TableContentType.PEPTIDE_FIT, peptideFits));
  }
 public synchronized void close() {
   // ToDo: Exception handling
   for (DataAccessController controller : controllers) {
     controller.close();
   }
 }
 /**
  * Check whether the given data access controller is foreground data access controller
  *
  * @param controller data access controller
  * @return boolean true if it is foreground data access controller
  */
 public synchronized boolean isForegroundDataAccessController(DataAccessController controller) {
   return foregroundController != null && foregroundController.equals(controller);
 }