/** {@inheritDoc} */
 @Override
 public void run() {
   Activator.getLogger().log(Level.FINE, "Starting {0}", ArchiveFetchJob.this); // $NON-NLS-1$
   final BenchmarkTimer timer = new BenchmarkTimer();
   long samples = 0;
   final int bins = Preferences.getPlotBins();
   final ArchiveDataSource archives[] = item.getArchiveDataSources();
   List<ArchiveDataSource> sourcesWhereChannelDoesntExist = new ArrayList<>();
   for (int i = 0; i < archives.length && !cancelled; ++i) {
     final ArchiveDataSource archive = archives[i];
     final String url = archive.getUrl();
     // Display "N/total", using '1' for the first sub-archive.
     synchronized (this) {
       message =
           NLS.bind(
               Messages.ArchiveFetchDetailFmt,
               new Object[] {archive.getName(), (i + 1), archives.length});
     }
     try {
       final ArchiveReader the_reader;
       synchronized (this) {
         the_reader = reader = ArchiveRepository.getInstance().getArchiveReader(url);
       }
       the_reader.enableConcurrency(concurrency);
       final ValueIterator value_iter;
       try {
         if (item.getRequestType() == RequestType.RAW)
           value_iter =
               the_reader.getRawValues(archive.getKey(), item.getResolvedName(), start, end);
         else
           value_iter =
               the_reader.getOptimizedValues(
                   archive.getKey(), item.getResolvedName(), start, end, bins);
       } catch (UnknownChannelException e) {
         // Do not immediately notify about unknown channels. First search for the data in all
         // archive
         // sources and only report this kind of errors at the end
         sourcesWhereChannelDoesntExist.add(archives[i]);
         continue;
       }
       // Get samples into array
       final List<VType> result = new ArrayList<VType>();
       while (value_iter.hasNext()) result.add(value_iter.next());
       samples += result.size();
       item.mergeArchivedSamples(the_reader.getServerName(), result);
       if (cancelled) break;
       value_iter.close();
     } catch (Exception ex) { // Tell listener unless it's the result of a 'cancel'?
       if (!cancelled) listener.archiveFetchFailed(ArchiveFetchJob.this, archive, ex);
       // Continue with the next data source
     } finally {
       synchronized (this) {
         if (reader != null) reader.close();
         reader = null;
       }
     }
   }
   if (!sourcesWhereChannelDoesntExist.isEmpty() && !cancelled) {
     listener.channelNotFound(
         ArchiveFetchJob.this,
         sourcesWhereChannelDoesntExist.size() < archives.length,
         sourcesWhereChannelDoesntExist.toArray(
             new ArchiveDataSource[sourcesWhereChannelDoesntExist.size()]));
   }
   timer.stop();
   if (!cancelled) listener.fetchCompleted(ArchiveFetchJob.this);
   Activator.getLogger()
       .log(
           Level.FINE,
           "Ended {0} with {1} samples in {2}", //$NON-NLS-1$
           new Object[] {ArchiveFetchJob.this, samples, timer});
 }
 /** Request thread to cancel its operation */
 public synchronized void cancel() {
   cancelled = true;
   synchronized (this) {
     if (reader != null) reader.cancel();
   }
 }