/** {@inheritDoc} */
  @Override
  protected DataExecutionResponse run(
      DataBuilderContext dataBuilderContext,
      DataFlowInstance dataFlowInstance,
      DataDelta dataDelta,
      DataFlow dataFlow,
      DataBuilderFactory builderFactory)
      throws DataBuilderFrameworkException, DataValidationException {
    CompletionService<DataContainer> completionExecutor =
        new ExecutorCompletionService<DataContainer>(executorService);
    ExecutionGraph executionGraph = dataFlow.getExecutionGraph();
    DataSet dataSet =
        dataFlowInstance.getDataSet().accessor().copy(); // Create own copy to work with
    DataSetAccessor dataSetAccessor = DataSet.accessor(dataSet);
    dataSetAccessor.merge(dataDelta);
    Map<String, Data> responseData = Maps.newTreeMap();
    Set<String> activeDataSet = Sets.newHashSet();

    for (Data data : dataDelta.getDelta()) {
      activeDataSet.add(data.getData());
    }
    List<List<DataBuilderMeta>> dependencyHierarchy = executionGraph.getDependencyHierarchy();
    Set<String> newlyGeneratedData = Sets.newHashSet();
    Set<DataBuilderMeta> processedBuilders =
        Collections.synchronizedSet(Sets.<DataBuilderMeta>newHashSet());
    while (true) {
      for (List<DataBuilderMeta> levelBuilders : dependencyHierarchy) {
        List<Future<DataContainer>> dataFutures = Lists.newArrayList();
        for (DataBuilderMeta builderMeta : levelBuilders) {
          if (processedBuilders.contains(builderMeta)) {
            continue;
          }
          // If there is an intersection, means some of it's inputs have changed. Reevaluate
          if (Sets.intersection(builderMeta.getConsumes(), activeDataSet).isEmpty()) {
            continue;
          }
          DataBuilder builder = builderFactory.create(builderMeta.getName());
          if (!dataSetAccessor.checkForData(builder.getDataBuilderMeta().getConsumes())) {
            break; // No need to run others, list is topo sorted
          }
          BuilderRunner builderRunner =
              new BuilderRunner(
                  dataBuilderExecutionListener,
                  dataFlowInstance,
                  builderMeta,
                  dataDelta,
                  responseData,
                  builder,
                  dataBuilderContext,
                  processedBuilders,
                  dataSet);
          Future<DataContainer> future = completionExecutor.submit(builderRunner);
          dataFutures.add(future);
        }

        // Now wait for something to complete.
        int listSize = dataFutures.size();
        for (int i = 0; i < listSize; i++) {
          try {
            DataContainer responseContainer = completionExecutor.take().get();
            Data response = responseContainer.getGeneratedData();
            if (responseContainer.isHasError()) {
              if (null != responseContainer.getValidationException()) {
                throw responseContainer.getValidationException();
              }

              throw responseContainer.getException();
            }
            if (null != response) {
              dataSetAccessor.merge(response);
              responseData.put(response.getData(), response);
              activeDataSet.add(response.getData());
              if (null != dataFlow.getTransients()
                  && !dataFlow.getTransients().contains(response.getData())) {
                newlyGeneratedData.add(response.getData());
              }
            }
          } catch (InterruptedException e) {
            throw new DataBuilderFrameworkException(
                DataBuilderFrameworkException.ErrorCode.BUILDER_EXECUTION_ERROR,
                "Error while waiting for error ",
                e);
          } catch (ExecutionException e) {
            throw new DataBuilderFrameworkException(
                DataBuilderFrameworkException.ErrorCode.BUILDER_EXECUTION_ERROR,
                "Error while waiting for error ",
                e.getCause());
          }
        }
      }
      if (newlyGeneratedData.contains(dataFlow.getTargetData())) {
        // logger.debug("Finished running this instance of the flow. Exiting.");
        break;
      }
      if (newlyGeneratedData.isEmpty()) {
        // logger.debug("Nothing happened in this loop, exiting..");
        break;
      }
      //            StringBuilder stringBuilder = new StringBuilder();
      //            for(String data : newlyGeneratedData) {
      //                stringBuilder.append(data + ", ");
      //            }
      // logger.info("Newly generated: " + stringBuilder);
      activeDataSet.clear();
      activeDataSet.addAll(newlyGeneratedData);
      newlyGeneratedData.clear();
      if (!dataFlow.isLoopingEnabled()) {
        break;
      }
    }
    DataSet finalDataSet = dataSetAccessor.copy(dataFlow.getTransients());
    dataFlowInstance.setDataSet(finalDataSet);
    return new DataExecutionResponse(responseData);
  }
    @Override
    public DataContainer call() throws Exception {

      for (DataBuilderExecutionListener listener : dataBuilderExecutionListener) {
        try {
          listener.beforeExecute(dataFlowInstance, builderMeta, dataDelta, responseData);
        } catch (Throwable t) {
          logger.error("Error running pre-execution execution listener: ", t);
        }
      }
      try {
        Data response =
            builder.process(
                dataBuilderContext.immutableCopy(
                    dataSet.accessor().getAccesibleDataSetFor(builder)));
        // logger.debug("Ran " + builderMeta.getName());
        procesedBuilders.add(builderMeta);
        for (DataBuilderExecutionListener listener : dataBuilderExecutionListener) {
          try {
            listener.afterExecute(dataFlowInstance, builderMeta, dataDelta, responseData, response);
          } catch (Throwable t) {
            logger.error("Error running post-execution listener: ", t);
          }
        }
        if (null != response) {
          Preconditions.checkArgument(
              response.getData().equalsIgnoreCase(builderMeta.getProduces()),
              String.format(
                  "Builder is supposed to produce %s but produces %s",
                  builderMeta.getProduces(), response.getData()));
          response.setGeneratedBy(builderMeta.getName());
        }
        return new DataContainer(builderMeta, response);
      } catch (DataBuilderException e) {
        logger.error("Error running builder: " + builderMeta.getName());
        for (DataBuilderExecutionListener listener : dataBuilderExecutionListener) {
          try {
            listener.afterException(dataFlowInstance, builderMeta, dataDelta, responseData, e);

          } catch (Throwable error) {
            logger.error("Error running post-execution listener: ", error);
          }
        }
        return new DataContainer(
            builderMeta,
            new DataBuilderFrameworkException(
                DataBuilderFrameworkException.ErrorCode.BUILDER_EXECUTION_ERROR,
                "Error running builder: " + builderMeta.getName(),
                e.getDetails(),
                e));

      } catch (DataValidationException e) {
        logger.error("Validation error in data produced by builder" + builderMeta.getName());
        for (DataBuilderExecutionListener listener : dataBuilderExecutionListener) {
          try {
            listener.afterException(dataFlowInstance, builderMeta, dataDelta, responseData, e);

          } catch (Throwable error) {
            logger.error("Error running post-execution listener: ", error);
          }
        }
        return new DataContainer(
            builderMeta,
            new DataValidationException(
                DataValidationException.ErrorCode.DATA_VALIDATION_EXCEPTION,
                "Error running builder: " + builderMeta.getName(),
                new DataExecutionResponse(responseData),
                e.getDetails(),
                e));

      } catch (Throwable t) {
        logger.error("Error running builder: " + builderMeta.getName());
        for (DataBuilderExecutionListener listener : dataBuilderExecutionListener) {
          try {
            listener.afterException(dataFlowInstance, builderMeta, dataDelta, responseData, t);

          } catch (Throwable error) {
            logger.error("Error running post-execution listener: ", error);
          }
        }
        Map<String, Object> objectMap = new HashMap<String, Object>();
        objectMap.put("MESSAGE", t.getMessage());
        return new DataContainer(
            builderMeta,
            new DataBuilderFrameworkException(
                DataBuilderFrameworkException.ErrorCode.BUILDER_EXECUTION_ERROR,
                "Error running builder: " + builderMeta.getName() + t.getMessage(),
                objectMap,
                t));
      }
    }