class RebuildBrowseNodesManager extends StateGuardLifecycleSupport {

  @Override
  protected void doStart() { // NOSONAR
    if (!automaticRebuildEnabled) {
      return;
    }

    Stopwatch sw = Stopwatch.createStarted();
    try {
      Collection<Bucket> buckets = inTx(componentDatabaseInstanceProvider).call(db -> {
        return stream(bucketEntityAdapter.browse(db)).filter(bucket -> {
          if (bucket.attributes().contains(P_PENDING_DELETION)) {
            log.debug("browse_node table won't be rebuilt for bucket={} as it is marked for deletion", id(bucket));
            return false;
          }
          boolean hasAssets = !execute(db, SELECT_ANY_ASSET_BY_BUCKET, singletonMap("bucket", id(bucket)))
              .isEmpty();
          boolean hasBrowseNodes = !execute(db, SELECT_ANY_BROWSE_NODE_BY_BUCKET,
              singletonMap("repositoryName", bucket.getRepositoryName()))
              .isEmpty();

          if (hasAssets ^ hasBrowseNodes) {
            log.debug("browse_node table will be rebuilt for bucket={}", id(bucket));
            return true;
          }
          else if (!hasAssets) {
            log.debug("browse_node table won't be populated as there are no assets for bucketId={}", id(bucket));
          }
          else {
            log.debug("browse_node table already populated for bucketId={}", id(bucket));
          }
          return false;
        }).collect(toList());
      });

      String repositoryNames = buckets.stream().map(Bucket::getRepositoryName).collect(Collectors.joining(","));

      if (!Strings2.isEmpty(repositoryNames)) {
        boolean existingTask = taskScheduler.findAndSubmit(RebuildBrowseNodesTaskDescriptor.TYPE_ID,
            ImmutableMap.of(RebuildBrowseNodesTaskDescriptor.REPOSITORY_NAME_FIELD_ID, repositoryNames));
        if (!existingTask) {
          launchNewTask(repositoryNames);
        }
      }
    }
    catch (Exception e) {
      log.error("Failed to determine if the browse nodes need to be rebuilt for any repositories", e);
    }
    log.debug("scheduling rebuild browse nodes tasks took {} ms", sw.elapsed(TimeUnit.MILLISECONDS));
  }

  @Inject public  RebuildBrowseNodesManager(@Named(ComponentDatabase.NAME)
                                   final Provider<DatabaseInstance> componentDatabaseInstanceProvider,
                                   final TaskScheduler taskScheduler,
                                   final BrowseNodeConfiguration configuration,
                                   final BucketEntityAdapter bucketEntityAdapter);

}